[Back to DOS SWAG index] [Back to Main SWAG index] [Original]

    {
    From: RANDALL WOODMAN
    Subj: CMOS Info

      Does anyone know how to get the hard drive type(s) from CMOS ?
    }

    USES DOS,CRT;

    TYPE
      String80 = STRING [80];  { some general purpose string types }
      String40 = STRING [40];
      String30 = STRING [30];
      String20 = STRING [20];
      String12 = STRING [12];
      String10 = STRING [10];
      String5  = STRING [5];

      CMOSRec = RECORD
        Found     : BOOLEAN;  { was a CMOS found to exist }
        CmosDate  : String30; { the date found in CMOS }
        CmosTime  : String30; { the time found in CMOS }
        VideoType : String10; { Type of video found in CMOS }
        Coproc    : BOOLEAN;  { does CMOS report a math coprocessor }
        FloppyA   : String12; { type of floppy drive for A }
        FloppyB   : String12; { Type of floppy drive for B }
        Hard0     : BYTE;     { Type of hard drive for drive 0 }
        Hard1     : BYTE;     { Type of hard drive for Drive 1 }
        ConvenRam : WORD;     { amount of conventional ram indicated }
        ExtendRam : WORD;     { amount of extended Ram indicated }
        checkSum  : BOOLEAN;  { Did checksum pass }
      END; { CMOS Rec }

    CONST
      { values of constants for CMOS }
      DayName : ARRAY [0..7] OF STRING [9] = ('Sunday', 'Monday', 'Tuesday',
                                              'Wednesday', 'Thursday', 'Friday',
                                              'Saturday', 'Sunday');
      MonthName : ARRAY [0..12] OF STRING [9] = ('???', 'January', 'February', 'March',
                                              'April', 'May', 'June', 'July',
                                              'August', 'September', 'October',
                                              'November', 'December');
      ScreenName : ARRAY [0..3] OF STRING [10] = ('EGA/VGA', 'CGA 40col',
                                               'CGA 80col', 'Monochrome');
      FloppyName : ARRAY [0..5] OF STRING [11] = ('none', '5.25" 360K',
                                               '5.25" 1.2M', '3.5"  720K',
                                               '3.5"  1.44M', '3.5"  2.88M');
      CMOSport : BYTE = $70; { port to access the CMOS }

      Country  : BYTE = 0;  { used for country date format }

    {===========================================================================}

    VAR
      Regs             : REGISTERS; { General purpose variable to access
                                      registers }
      CMOS             : CMOSRec;   { variable to hold CMOS data }

    FUNCTION nocarry : BOOLEAN;
    { returns the status of the carry flag }
    BEGIN
      nocarry := regs.flags AND fcarry = $0000
    END; {nocarry}

    {---------------------------------------------------------------------------}

    FUNCTION ByteToWord (ByteA, ByteB : BYTE) : WORD;
    BEGIN
       ByteToWord := WORD (ByteB) SHL 8 + ByteA
    END; {cbw}

    {---------------------------------------------------------------------------}

    FUNCTION BitIsSet (CheckWord : WORD; AndValue : WORD) : BOOLEAN;
    { returns true if the bit(s) indicated in AndValue are set in CheckByte }
    BEGIN
      BitIsSet := CheckWord AND AndValue = AndValue;
    END;

    {---------------------------------------------------------------------------}

    FUNCTION ReadCMOS (ADDR : BYTE) : BYTE;
    { read a value from the CMOS }
    BEGIN
      IF CMOSport = $70 THEN
      BEGIN
        INLINE ($FA);
        Port [CMOSport] := ADDR;
        readCMOS := Port [CMOSport + 1];
        INLINE ($FB)
      END
    END; {readCMOS}

    {---------------------------------------------------------------------------}

    FUNCTION addzero (b : BYTE) : string5;
    VAR
      c2 : STRING [2];
    BEGIN
      STR (b : 0, c2);
      IF b < 10 THEN
        c2 := '0' + c2;
      addzero := c2
    END; {addzero}

    {---------------------------------------------------------------------------}

    FUNCTION ChangeBCD (b : BYTE) : BYTE;
    { change a BCD into a byte structure }
    BEGIN
      ChangeBCD := (b AND $0F) + ( (b SHR 4) * 10)
    END; {ChangeBCD}

    {---------------------------------------------------------------------------}

    FUNCTION Long2Str (Long : LONGINT) : STRING;
    VAR Stg : STRING;
    BEGIN
      STR (Long, Stg);
      Long2Str := Stg;
    END;

    FUNCTION  HexL (argument : LONGINT) : STRING; Assembler;
      asm
         cld
         les    di, @result
         mov    al, 8                   { store string length }
         stosb
         mov    cl, 4                  { shift count }

         mov    dx, WORD PTR Argument + 2 { hi word }
         call   @1                     { convert dh to ascii }
         mov    dh, dl                 { lo byte of hi word }
         call   @1                     { convert dh to ascii }
         mov    dx, WORD PTR Argument   { lo word }
         call   @1                     { convert dh to ascii }
         mov    dh, dl                 { lo byte of lo word }
         call   @1                     { convert dh to ascii }
         jmp    @2

       @1 :
         mov    al, dh                 { 1 byte }
         AND    al, 0fh                { low nybble }
         add    al, 90h
         daa
         adc    al, 40h
         daa
         mov    ah, al                 { store }
         mov    al, dh                 { 1 byte }
         SHR    al, cl                 { get high nybble }
         add    al, 90h
         daa
         adc    al, 40h
         daa
         stosw                         { move characters to result }
         retn                          { return near }
       @2 :
      END;

    FUNCTION GetCMOSDate : String30;
    { gets the date found in the CMOS and returns it in string format }
    VAR
      Date,
      Century,
      Year,
      Month : BYTE;
      WorkStr : String30;
    BEGIN
      WorkStr := '';
      date    := ChangeBCD (readCMOS (7) );
      century := ChangeBCD (readCMOS ($32) );
      year    := ChangeBCD (readCMOS (9) );
      month   := ChangeBCD (readCMOS (8) );
      CASE country OF
        0, 3..255 :
          WorkStr := WorkStr + Monthname [month] + ' ' + Long2Str (date) + ', ' + Long2Str (century) + addzero (year);
        1 :
          WorkStr := WorkStr + Long2Str (date) + ', ' + Monthname [month] + ' ' + Long2Str (century) + addzero (Year);
        2 :
          WorkStr := WorkStr + Long2Str (century) + addzero (Year) + ', ' + Monthname [month] + ' ' + Long2Str (date);
      END; {case}
      GetCMosDate := workStr;
    END; { GetCMOSDate }

    {---------------------------------------------------------------------------}

    FUNCTION GetCmosTime : String30;
    { returns the time as found in the CMOS }
    VAR
      CH : CHAR;
      Hour,
      Min,
      Sec  : BYTE;
      WorkStr : String30;
      IsPM    : BOOLEAN;
    BEGIN
      workStr := '';
      hour := ChangeBCD (readCMOS (4) );
      min := ChangeBCD (readCMOS (2) );
      sec := ChangeBCD (readCMOS (0) );
      IsPm := FALSE;
      CASE hour OF
            0 : hour := 12;
            1..11 : hour := hour;
            12 : IsPM := TRUE;
            13..23 : BEGIN
                      IsPM := TRUE;
                      hour := hour - 12
                    END;
      END; {case}
      WorkStr := WorkStr + AddZero (hour) + ':' + addzero (min) + ':' + addzero (sec);
      IF IsPM THEN
        workStr := WorkStr + ' PM'
      ELSE
        WorkStr := WorkStr + ' AM';
      GetCMOSTime := WorkStr;
    END; { GetCmosTime }

    {---------------------------------------------------------------------------}

    FUNCTION GetCmosCheckSum : BOOLEAN;
    { performs checksum on CMOS and returns true if ok }
    VAR
      CheckSum1,
      CheckSum2 : WORD;
      Count     : BYTE;
    BEGIN
      checksum1 := 0;
      FOR count := $10 TO $2D DO
        INC (checksum1, readCMOS (count) );
      checksum2 := (WORD (256) * readCMOS ($2E) ) + readCMOS ($2F);
      IF checksum1 = checksum2 THEN
        GetCmosCheckSum := TRUE
      ELSE
        GetCmosCheckSum := FALSE;
    END; { GetCmosCheckSum }

    {---------------------------------------------------------------------------}

    PROCEDURE GetCMos;
    { gets the cmos record if it exist }
    VAR
      Floppy : BYTE;
    BEGIN
      FILLCHAR (CMOS, SIZEOF (CMos), 0);
      regs.AH := $C0;
      INTR ($15, regs);
      IF nocarry OR (Mem [$F000 : $FFFE] <= $FC) THEN
      WITH CMOS DO
      BEGIN
        Found := TRUE;
        CMOSDate := GetCMOSDate;
        CMOSTime := GetCmosTime;
        VideoType := ScreenName [ (readCMOS ($14) SHR 4) AND 3];
        CoProc := BitIsSet (readCMOS ($14), 1);
        Floppy := readCMOS ($10);
        IF (Floppy SHR 4) < 5 THEN
          FloppyA := FloppyName [floppy SHR 4]
        ELSE
          FloppyA := 'Unknown ' + HexL (floppy SHR 4);
        IF (floppy AND $0F) < 5 THEN
          FloppyB := FloppyName [floppy AND $0F]
        ELSE
          FloppyB := 'Unknown ' + HexL (floppy AND $0F);

        Hard0 := readCMOS ($12);
        Hard0 := Hard0 SHR 4;
        Hard1 := ReadCmos ($12);
        Hard1 := Hard1 AND $0F;
        IF Hard0 = $F THEN
          Hard0 := readCMOS ($19)
        ELSE Hard0 := $FF; { error }
        IF Hard1 = $F THEN
          Hard1 := readCMOS ($1A)
        ELSE Hard1 := $FF;
        ConvenRam := WORD (256) * readCMOS ($16) + readCMOS ($15); { value in K }
        ExtendRam := WORD (256) * readCMOS ($18) + readCMOS ($17); { value in K }
        CheckSum := GetCmosCheckSum;
      END
      ELSE
        CMOS.Found := FALSE;
    END;

    BEGIN
    ClrScr;
    GetCMos;
    With CMOS DO
         BEGIN
         WriteLn('Date     : ',CMosDate);
         WriteLn('Time     : ',CMosTime);
         WriteLn('Video    : ',VideoType);
         WriteLn('Math     : ',CoProc);
         WriteLn('FloppyA  : ',FloppyA);
         WriteLn('FloppyB  : ',FloppyB);
         WriteLn('Hard #1  : ',Hard0);
         WriteLn('Hard #2  : ',Hard1);
         WriteLn('Base Ram : ',ConvenRam,'K');
         WriteLn('Ext Ram  : ',ExtendRam,'K');
         ReadKey;
         END;
    END.

[Back to DOS SWAG index] [Back to Main SWAG index] [Original]