home *** CD-ROM | disk | FTP | other *** search
- #pragma inline
- #pragma option -1 /* generate 286 instructions */
- /* RTCHDW.C -- AT Real-Time Clock control functions
- * Author Jim Mischel. Last update 03/22/92 */
- #include <stdio.h>
- #include <dos.h>
- #include "rtc.h"
-
- /* Loop until "Update in Progress" bit is clear */
- static void WaitForUpdate (void) {
- while (ReadCMOS (SRA) & UIP)
- ;
- }
-
- /* Read Value from CMOS RAM */
- int ReadCMOS (int Addr) {
- int ch;
- asm pushf /* save interrupt flag */
- disable ();
- if (Addr < SRA) WaitForUpdate ();
- outportb (CMOS_Control, Addr);
- ch = inportb (CMOS_Data);
- asm popf /* restore interrupt flag */
- return ch;
- } /* ReadCMOS */
-
- /* Write Value to CMOS RAM */
- void WriteCMOS (int Addr, int Value) {
- asm pushf /* save interrupt flag */
- disable ();
- if (Addr < SRA) WaitForUpdate ();
- outportb (CMOS_Control, Addr);
- outportb (CMOS_Data, Value);
- asm popf /* restore interrupt flag */
- } /* WriteCMOS */
-
- /* Compute and store new CMOS checksum */
- void NewCMOSChecksum (void) {
- int Loc, CheckSum = 0;
- for (Loc = 0x10; Loc < 0x2E; Loc++)
- CheckSum += ReadCMOS (Loc);
- WriteCMOS (0x2E, (CheckSum >> 8));
- WriteCMOS (0x2F, (CheckSum & 0xFF));
- }
-
- /* ISR pointers initially point to DummyIsr in case an
- * interrupt is enabled for which no ISR has been installed. */
- static void far DummyIsr (void) {
- }
-
- static void far (*PeriodicIsr) (void) = DummyIsr;
- static void far (*UpdateIsr) (void) = DummyIsr;
- static void far (*AlarmIsr) (void) = DummyIsr;
-
- /* Setup periodic interrupt frequency and ISR */
- int SetPeriodicInt (int Freq, void far (*isr)()) {
- if (ReadCMOS (SRB) & PIE)
- return 1; /* can't set -- already enabled */
- if (isr != NULL) PeriodicIsr = isr;
- /* set new periodic rate */
- WriteCMOS (SRA, (ReadCMOS (SRA) & 0xf0) | (Freq & 0x0f));
- return 0;
- }
-
- /* Setup update-ended ISR */
- int SetUpdateInt (void far (*isr)()) {
- if (ReadCMOS (SRB) & UIE)
- return 1; /* can't set -- already enabled */
- if (isr != NULL) UpdateIsr = isr;
- return 0;
- }
-
- /* Convert binary value (0-99) to BCD */
- static int BinToBCD (int Bin) {
- return ((Bin / 10) << 4) + (Bin % 10);
- }
-
- /* Setup alarm time and ISR */
- int SetAlarmInt (struct RTCTIME *Time, void far (*isr)()) {
- unsigned char srb;
- if (ReadCMOS (SRB) & AIE)
- return 1; /* already set, exit with error */
- if (isr != NULL) AlarmIsr = isr;
- srb = ReadCMOS (SRB);
- WriteCMOS (SRB, srb | 0x80); /* turn on SET bit */
- WriteCMOS (0x05, (Time->Hour < 0xc0) ?
- BinToBCD (Time->Hour) : Time->Hour);
- WriteCMOS (0x03, (Time->Min < 0xc0) ?
- BinToBCD (Time->Min) : Time->Min);
- WriteCMOS (0x01, (Time->Sec < 0xc0) ?
- BinToBCD (Time->Sec) : Time->Sec);
- WriteCMOS (SRB, srb); /* restore SET bit */
- return 0;
- }
-
- /* Enable individual RTC interrupts */
- void EnableRTCint (int Which) {
- WriteCMOS (SRB, (ReadCMOS (SRB) |
- (Which & (UF | PF | AF))));
- }
-
- /* Disable individual RTC interrupts */
- void DisableRTCint (int Which) {
- WriteCMOS (SRB, (ReadCMOS (SRB) &
- ~(Which & (UF | PF | AF))));
- }
-
- /* Reset individual RTC interrupts and ISRs */
- void ResetRTCint (int Which) {
- DisableRTCint (Which);
- if (Which & PIE) {
- PeriodicIsr = DummyIsr;
- /* reset rate to 1024 ticks/sec */
- WriteCMOS (SRA, (ReadCMOS (SRA) & 0xf0) | 6);
- }
- if (Which & UIE) UpdateIsr = DummyIsr;
- if (Which & AIE) AlarmIsr = DummyIsr;
- }
-
- static void far NewRTCint (void); /* ISR Prototype */
- static void interrupt (*OldRTCint) () = NULL; /* Old RTC ISR */
-
- /* Pointer to new RTC ISR */
- static void interrupt (*RTCintPtr) () =
- (void interrupt *)NewRTCint;
-
- /* Enable the RTC interrupt */
- void TimerOn (void) {
- disable ();
- if (OldRTCint == NULL) { /* save old RTC int vector */
- OldRTCint = getvect (RTCINT);
- setvect (RTCINT, RTCintPtr);
- }
- ReadCMOS (SRC); /* clear pending RTC interrupts... */
- /* ...and enable RTC interrupt */
- outportb (PIC2ctrl, inportb (PIC2ctrl) & 0xfe);
- enable ();
- }
-
- /* Disable RTC hardware interrupt */
- void TimerOff (void) {
- disable ();
- /* disable RTC interrupt */
- outportb (PIC2ctrl, inportb (PIC2ctrl) | 1);
- setvect (RTCINT, OldRTCint); /* reset RTC ISR */
- OldRTCint = NULL;
- enable ();
- }
-
- /* New INT 70H ISR. Because the state of the stack is unknown
- * when this function is entered, we must create a new stack
- * before doing any processing. As a result there can be no
- * automatic (i.e. stack) variables defined within this function. */
- /* Define stack size and number of stacks */
- #define StackSize 128
- #define Stacks 3
- #define SaveRecordSize 8
- static char NewStack[StackSize*Stacks];
-
- static unsigned char IntFlags;
-
- static void far NewRTCint (void) {
- /* save caller's context and setup new stack */
- asm xchg bp,[word ptr cs:SaveArea] /* get next stack area */
- asm cmp bp,Offset EndSaveArea /* last stack? */
- asm jc Around /* nope, OK */
- asm jmp StackError /* Stack overflow! */
- Around:
- asm mov [word ptr cs:bp+2],sp /* save stack */
- asm mov [word ptr cs:bp+4],ss
- asm mov sp,[word ptr cs:SaveArea] /* get and save... */
- asm mov [word ptr cs:bp+6],sp /* ...original BP */
- asm mov sp,[word ptr cs:bp] /* Setup new SP... */
- asm add bp,SaveRecordSize /* ...and point to... */
- asm mov [word ptr cs:SaveArea],bp /* ...next save area */
- asm mov bp,DGROUP
- asm mov ss,bp /* SS = local data segment */
- asm pusha /* save general registers... */
- asm push es /* ...and segment registers... */
- asm push ds /* ...on new stack */
- asm mov ds,bp /* ds = ss */
-
-
- /* Determine which interrupts occurred */
- IntFlags = ReadCMOS (SRC) & ReadCMOS (SRB);
- enable (); /* interrupts OK now */
- /* call appropriate interrupt routines */
- if (IntFlags & PF) (*PeriodicIsr) ();
- if (IntFlags & UF) (*UpdateIsr) ();
- if (IntFlags & AF) (*AlarmIsr) ();
- outportb (PIC2data, EOI); /* Reset interrupt controllers */
- outportb (PIC1data, EOI);
-
- /* restore caller's context and return */
- disable ();
- asm pop ds /* restore segment registers... */
- asm pop es
- asm popa /* ...and general registers */
- asm mov bp,[word ptr cs:SaveArea] /* Restore... */
- asm sub bp,SaveRecordSize /* ...save area pointer, */
- asm mov [word ptr cs:SaveArea],bp
- asm mov ss,[word ptr cs:bp+4] /* ...stack,... */
- asm mov sp,[word ptr cs:bp+2]
- asm pop bp /* ...and BP */
- asm iret
-
- /*
- * Stack overflow handler.
- * Display an error message and hang the system.
- */
- StackError:
- asm mov ax,cs
- asm mov ds,ax
- asm mov dx,offset OverflowMessage
- asm mov ah,9
- asm int 21h
- DeadLoop: /* system hangs here */
- asm jmp short DeadLoop
- /*** Local data ***/
- asm OverflowMessage = $
- asm db 13,10,7,'RTC Stack overflow'
- asm db 13,10,'System Halted$'
- asm SaveArea = $
- asm dw Offset SaveArea+2
- asm dw Offset DGROUP:NewStack + (Stacks * StackSize)
- asm dw 3 dup (?)
- asm dw Offset DGROUP:NewStack + ((Stacks-1) * StackSize)
- asm dw 3 dup (?)
- asm dw Offset DGROUP:NewStack + ((Stacks-2) * StackSize)
- asm dw 3 dup (?)
- asm EndSaveArea = $
- }
-