


        In addition to it's use in accessing the CMOS RAM, port 70h is 
        also used to enable or disable the non-maskable interrupt (NMI).  
        Because of this dual use of the port, you must be very careful 
        when accessing CMOS RAM, lest you disable NMI inadvertantly.
        
        You may look on this dual use of an I/O port as a strange quirk 
        of the AT hardware, but it's actually quite useful.  Remember, we 
        like to turn off interrupts before accessing the CMOS RAM.  There 
        are very few cases when we want to turn off NMI, but this just 
        happens to be one of them.  So, if we take care to always disable 
        NMI before accessing CMOS RAM and enable NMI after accessing CMOS 
        RAM, we'll be just fine.
        
        NMI is disabled by "OR-ing" the CMOS RAM address with 80h so that 
        the high bit of the value sent to port 70h is set.  This disables 
        NMI.  To re-enable NMI, we read CMOS register 0Dh--Status 
        Register D.  The reason we use Status Register D is because it is 
        a read-only register.  If a non-maskable interrupt occurs after 
        we set the CMOS RAM address but before we can read it, an errant 
        output to port 71h will not hurt anything.
        
        New ReadCMOS() and WriteCMOS() routines that correctly handle NMI 
        are below:
        
        /* 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 | 0x80);
            ch = inportb (CMOS_Data);
            outportb (CMOS_Control, SRD);  /* re-enable NMI */
            inportb (CMOS_Data);           /* and read SRD */
            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 | 0x80);
            outportb (CMOS_Data, Value);
            outportb (CMOS_Control, SRD);  /* re-enable NMI */
            inportb (CMOS_Data);           /* and read SRD */
            asm popf            /* restore interrupt flag */
        } /* WriteCMOS */



