Contributor: RANDALL WOODMAN { 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.