patch-2.4.15 linux/drivers/char/rtc.c

Next file: linux/drivers/char/serial.c
Previous file: linux/drivers/char/random.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.14/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
@@ -79,9 +79,11 @@
 #endif
 
 static unsigned long rtc_port;
-static int rtc_irq;
+static int rtc_irq = PCI_IRQ_NONE;
 #endif
 
+static int rtc_has_irq = 1;
+
 /*
  *	We sponge a minor off of the misc major. No need slurping
  *	up another valuable major dev number for this. If you add
@@ -198,6 +200,9 @@
 	unsigned long data;
 	ssize_t retval;
 	
+	if (rtc_has_irq == 0)
+		return -EIO;
+
 	if (count < sizeof(unsigned long))
 		return -EINVAL;
 
@@ -244,6 +249,22 @@
 {
 	struct rtc_time wtime; 
 
+#if RTC_IRQ
+	if (rtc_has_irq == 0) {
+		switch (cmd) {
+		case RTC_AIE_OFF:
+		case RTC_AIE_ON:
+		case RTC_PIE_OFF:
+		case RTC_PIE_ON:
+		case RTC_UIE_OFF:
+		case RTC_UIE_ON:
+		case RTC_IRQP_READ:
+		case RTC_IRQP_SET:
+			return -EINVAL;
+		};
+	}
+#endif
+
 	switch (cmd) {
 #if RTC_IRQ
 	case RTC_AIE_OFF:	/* Mask alarm int. enab. bit	*/
@@ -412,15 +433,18 @@
 			yrs = 73;
 		}
 #endif
+		/* These limits and adjustments are independant of
+		 * whether the chip is in binary mode or not.
+		 */
+		if (yrs > 169) {
+			spin_unlock_irq(&rtc_lock);
+			return -EINVAL;
+		}
+		if (yrs >= 100)
+			yrs -= 100;
+
 		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
 		    || RTC_ALWAYS_BCD) {
-			if (yrs > 169) {
-				spin_unlock_irq(&rtc_lock);
-				return -EINVAL;
-			}
-			if (yrs >= 100)
-				yrs -= 100;
-
 			BIN_TO_BCD(sec);
 			BIN_TO_BCD(min);
 			BIN_TO_BCD(hrs);
@@ -550,13 +574,16 @@
 static int rtc_release(struct inode *inode, struct file *file)
 {
 #if RTC_IRQ
+	unsigned char tmp;
+
+	if (rtc_has_irq == 0)
+		goto no_irq;
+
 	/*
 	 * Turn off all interrupts once the device is no longer
 	 * in use, and clear the data.
 	 */
 
-	unsigned char tmp;
-
 	spin_lock_irq(&rtc_lock);
 	tmp = CMOS_READ(RTC_CONTROL);
 	tmp &=  ~RTC_PIE;
@@ -574,6 +601,7 @@
 	if (file->f_flags & FASYNC) {
 		rtc_fasync (-1, file, 0);
 	}
+no_irq:
 #endif
 
 	spin_lock_irq (&rtc_lock);
@@ -592,6 +620,9 @@
 {
 	unsigned long l;
 
+	if (rtc_has_irq == 0)
+		return 0;
+
 	poll_wait(file, &rtc_wait, wait);
 
 	spin_lock_irq (&rtc_lock);
@@ -669,12 +700,17 @@
 	return -EIO;
 
 found:
+	if (rtc_irq == PCI_IRQ_NONE) {
+		rtc_has_irq = 0;
+		goto no_irq;
+	}
+
 	/*
 	 * 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.
 	 */
-	if(request_irq(rtc_irq, rtc_interrupt, SA_INTERRUPT, "rtc", (void *)&rtc_port)) {
+	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.
@@ -682,6 +718,7 @@
 		printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq);
 		return -EIO;
 	}
+no_irq:
 #else
 	if (check_region (RTC_PORT (0), RTC_IO_EXTENT))
 	{
@@ -712,8 +749,10 @@
 	
 	uip_watchdog = jiffies;
 	if (rtc_is_updating() != 0)
-		while (jiffies - uip_watchdog < 2*HZ/100)
+		while (jiffies - uip_watchdog < 2*HZ/100) { 
 			barrier();
+			cpu_relax();
+		}
 	
 	spin_lock_irq(&rtc_lock);
 	year = CMOS_READ(RTC_YEAR);
@@ -766,11 +805,13 @@
 	misc_deregister(&rtc_dev);
 
 #ifdef __sparc__
-	free_irq (rtc_irq, &rtc_port);
+	if (rtc_has_irq)
+		free_irq (rtc_irq, &rtc_port);
 #else
 	release_region (RTC_PORT (0), RTC_IO_EXTENT);
 #if RTC_IRQ
-	free_irq (RTC_IRQ, NULL);
+	if (rtc_has_irq)
+		free_irq (RTC_IRQ, NULL);
 #endif
 #endif /* __sparc__ */
 }
@@ -946,8 +987,10 @@
 	 */
 
 	if (rtc_is_updating() != 0)
-		while (jiffies - uip_watchdog < 2*HZ/100)
+		while (jiffies - uip_watchdog < 2*HZ/100) {
 			barrier();
+			cpu_relax();
+		}
 
 	/*
 	 * Only the values that we read from the RTC are set. We leave

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)