[PATCH] Persistent RTC, against 2.2.16

Chris McClellen (chris@transtech.cc)
Wed, 9 Aug 2000 11:30:17 -0400


This is a multi-part message in MIME format.

------=_NextPart_000_01A7_01C001F5.313D7360
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

The problem:

We have machines in the field that we would like to power cycle;
that is, turn off, and have them turn themselves back on w/o a human
in general. This of course won't always work, but it will in general.

This is possible -- we can halt w/poweroff. But, before we do, we can
set the rtc alarm via /dev/rtc. We can also set up the interrupt on
alarm via /dev/rtc. The mobos have wake-on-alarm, and they will
power themselves back on when the alarm interrupt goes off.

So, we can set the alarm, poweroff, and it will powerback on....

Except that /dev/rtc will clear the alarm interrupt enable when the
device is closed (rtc_release). In fact, it clears all rtc interrupt
enables. So, when the process that sets AIE exits, AIE gets cleared,
thwarting our efforts.

Solution:

Added a RTC_PERSIST status that can be read/set via ioctls.

By default it is _NOT_ set, giving original /dev/rtc behavior.

When Set the following occurs:
- AIE is not cleared when rtc_release is called. The other interrupt
enables get cleared as normal. I thought this would be desired, but
it would be trivial to not clear the other IEs if persist is set.
- RTC_PERSIST remains between opens/closes.
+ If we cleared persist on close, then during halt someone could
open/close /dev/rtc and undo our AIE. Thus, once set, RTC_PERSIST
remains between open/close until unset via ioctl.

We would like to see this make it into the official kernel
so we dont have to maintain special patched kernels in the field.
Of course we can, but it would be nice to be able to just use stock
kernels in the future.

See the attached patch.

------=_NextPart_000_01A7_01C001F5.313D7360
Content-Type: application/octet-stream;
name="patch.rtc.persist"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="patch.rtc.persist"

diff -c -r linux.orig/drivers/char/rtc.c linux/drivers/char/rtc.c=0A=
*** linux.orig/drivers/char/rtc.c Fri Jan 15 01:58:47 1999=0A=
--- linux/drivers/char/rtc.c Wed Jul 26 14:54:46 2000=0A=
***************=0A=
*** 98,103 ****=0A=
--- 98,105 ----=0A=
=0A=
#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */=0A=
#define RTC_TIMER_ON 0x02 /* missed irq timer active */=0A=
+ #define RTC_PERSIST 0x04 /* Tells us whether RTC wishes=0A=
+ to keep its alarm setup */=0A=
=0A=
unsigned char rtc_status =3D 0; /* bitmapped status byte. */=0A=
unsigned long rtc_freq =3D 0; /* Current periodic IRQ rate */=0A=
***************=0A=
*** 413,418 ****=0A=
--- 415,440 ----=0A=
restore_flags(flags);=0A=
return 0;=0A=
}=0A=
+ case RTC_PERSIST_READ:=0A=
+ {=0A=
+ unsigned long persist =3D 0;=0A=
+ persist =3D (rtc_status & RTC_PERSIST) =3D=3D RTC_PERSIST;=0A=
+ return put_user(persist, (unsigned long*) arg);=0A=
+ }=0A=
+ case RTC_PERSIST_SET:=0A=
+ {=0A=
+ if (!capable(CAP_SYS_TIME))=0A=
+ return -EACCES;=0A=
+ =0A=
+ if (arg)=0A=
+ rtc_status |=3D RTC_PERSIST;=0A=
+ else=0A=
+ rtc_status &=3D ~RTC_PERSIST;=0A=
+ =0A=
+ return 0;=0A=
+ }=0A=
+ =0A=
+ =0A=
#ifdef __alpha__=0A=
case RTC_EPOCH_READ: /* Read the epoch. */=0A=
{=0A=
***************=0A=
*** 469,475 ****=0A=
cli();=0A=
tmp =3D CMOS_READ(RTC_CONTROL);=0A=
tmp &=3D ~RTC_PIE;=0A=
! tmp &=3D ~RTC_AIE;=0A=
tmp &=3D ~RTC_UIE;=0A=
CMOS_WRITE(tmp, RTC_CONTROL);=0A=
CMOS_READ(RTC_INTR_FLAGS);=0A=
--- 491,505 ----=0A=
cli();=0A=
tmp =3D CMOS_READ(RTC_CONTROL);=0A=
tmp &=3D ~RTC_PIE;=0A=
! =0A=
! /* If persist flag is set, we dont want to clear out the=0A=
! * alarm on close. Also note that we dont want to =0A=
! * clear RTC_PERSIST on close either! We want it preserved=0A=
! * across open/close once its set.=0A=
! */=0A=
! if ((rtc_status & RTC_PERSIST) !=3D RTC_PERSIST)=0A=
! tmp &=3D ~RTC_AIE;=0A=
! =0A=
tmp &=3D ~RTC_UIE;=0A=
CMOS_WRITE(tmp, RTC_CONTROL);=0A=
CMOS_READ(RTC_INTR_FLAGS);=0A=
***************=0A=
*** 668,674 ****=0A=
"update_IRQ\t: %s\n"=0A=
"periodic_IRQ\t: %s\n"=0A=
"periodic_freq\t: %ld\n"=0A=
! "batt_status\t: %s\n",=0A=
(ctrl & RTC_DST_EN) ? "yes" : "no",=0A=
(ctrl & RTC_DM_BINARY) ? "no" : "yes",=0A=
(ctrl & RTC_24H) ? "yes" : "no",=0A=
--- 698,705 ----=0A=
"update_IRQ\t: %s\n"=0A=
"periodic_IRQ\t: %s\n"=0A=
"periodic_freq\t: %ld\n"=0A=
! "batt_status\t: %s\n"=0A=
! "persist\t\t: %s\n",=0A=
(ctrl & RTC_DST_EN) ? "yes" : "no",=0A=
(ctrl & RTC_DM_BINARY) ? "no" : "yes",=0A=
(ctrl & RTC_24H) ? "yes" : "no",=0A=
***************=0A=
*** 677,683 ****=0A=
(ctrl & RTC_UIE) ? "yes" : "no",=0A=
(ctrl & RTC_PIE) ? "yes" : "no",=0A=
rtc_freq,=0A=
! batt ? "okay" : "dead");=0A=
=0A=
return p - buf;=0A=
}=0A=
--- 708,715 ----=0A=
(ctrl & RTC_UIE) ? "yes" : "no",=0A=
(ctrl & RTC_PIE) ? "yes" : "no",=0A=
rtc_freq,=0A=
! batt ? "okay" : "dead", =0A=
! (rtc_status & RTC_PERSIST) ? "yes" : "no");=0A=
=0A=
return p - buf;=0A=
}=0A=
diff -c -r linux.orig/include/linux/mc146818rtc.h =
linux/include/linux/mc146818rtc.h=0A=
*** linux.orig/include/linux/mc146818rtc.h Tue May 11 13:37:15 1999=0A=
--- linux/include/linux/mc146818rtc.h Wed Jul 26 13:35:53 2000=0A=
***************=0A=
*** 144,149 ****=0A=
--- 144,151 ----=0A=
#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate =
*/=0A=
#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch =
*/=0A=
#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch =
*/=0A=
+ #define RTC_PERSIST_READ _IOR('p', 0x0f, unsigned long) /* get =
persist flag*/=0A=
+ #define RTC_PERSIST_SET _IOW('p', 0x10, unsigned long) /* set =
persist flag*/=0A=
=0A=
=0A=
#endif /* _MC146818RTC_H */=0A=

------=_NextPart_000_01A7_01C001F5.313D7360--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/