//Ryan Alswede
//Pos Code reader, C++ Version 1.0
//5-09-02
#include <iostream.h>
#include <stdlib.h>
#include <conio.h>
#define KEYINT 0x0016
#define GETKEY 0x010
#pragma intrinsic(inp, outp)
int main()
{
int i;
int x;
int TotalSlots;
int POSx;
system ("cls");
outp(0x75, 1);
outp(0x74, 0x8E);
cout << "MCA PS/2 Extended CMOS Adapter POS Viewer"<< endl;
cout << "Views the POS settings for installed microchannel adapters"
<< endl;
cout << "Please only use this on microchannel computers" << endl;
cout << "Not responsible for damage with program misuse" << endl;
cout << endl;
TotalSlots = inp(0x76);
outp (0x75, 0);
cout << "Total number of MCA slots on this computer:
"<<hex<<TotalSlots << endl;
cout << endl;
cout << "Slot Number POS(0) POS(1) POS(2) POS(3) POS(4)
POS _(5) POS(6)" << endl;
for (i = 1; i = (TotalSlots * 35); i = i+35)
{
cout << " " << hex << ((i / 35) + 1) + " ";
for(x = 0; x=6; ++i)
{ outp(0x74, (i - 1) + x);
POSx = inp(0x76);
cout << " ";
if (POSx < 10)
{
cout << "0";
cout<< hex << POSx;
}
}
cout << endl;
}
cout << endl;
cout << "Description:" << endl;
cout << "Slot number is the number of the MCA slot." << endl;
cout << "POS(0) is the Least-Significant Byte (LSB) of the adapter
ID." << endl;
cout << "POS(1) is the Most-Significant Byte (MSB) of the adapter ID."
<< endl;
cout << "If both POS(0) & POS(1) are 'FF', an adapter is not installed
on that_ slot." << endl;
cout << "POS(2) is from the adapter ADF 'Numbytes' entry, the number
of POS _ bytes used." << endl;
cout << "POS(3) through POS(6) are the adapter POS settings as
configured in _ the ADF." << endl;
return 0;
}
Strictly speaking, all access to extended CMOS should be done within an
"interrupts disabled" section of code. Also, the "address register pair" 75h
(low byte) and 76h (high byte) should be set back to 0186h before leaving
this section. Same for RTC/CMOS as regards "interrupts disabled" and which
should be left pointing to 1Eh.
--
Cheers,
Tim
> Also, the "address register pair" 75h (low byte) and 76h
> (high byte) should be set back to 0186h before leaving
> this section. Same for RTC/CMOS as regards "interrupts
> disabled" and which should be left pointing to 1Eh.
Don't you mean 75h (high byte) and 74h (low byte)? Register 76h is for
retrieving the value of the Extended CMOS location pointed to by registers
75h & 74h. Why 0186h? Because that is an unassigned byte that is used to
check if the MCA Extended CMOS exists by writing, then reading, a value to
that location. I don't have this done in my routines, but will modify them
as soon as I can.
I recommend a book like "Undocumented PC" for programmers that choose to
bypass the BIOS routines & write/read directly to the RTC/CMOS chip. My
individual results were errors up to 10% of the time if not carefully
programmed! The reason for this is during a clock update cycle all chip
registers can be inaccessable. This doesn't hold as true for the Extended
CMOS chip, since it is normally separate from the RTC functions.
David
Da...@gilanet.com
> > Strictly speaking, all access to extended CMOS should
> > be done within an "interrupts disabled" section of code.
>
> Exactly, but remember to re-enable interrupts when done. On an
> Intel-based Assembler this is very easily done with "CLI" (Clear
Interrupts)
> & "STI" (Set Interrupts). BTW, for those worried about it, the statements
> just enable/disable *hardware-based* interrupts.
This should, additionally, involve masking the NMI processor input by
reading port 70h, "saving" the current value read, ORing in 80h (NMI mask)
and writing this out to 70h. Furthermore, *any* output to port 70h *must* be
followed by an input/output operation on port 71h, otherwise incorrect
operation of the RTC/CMOS may occur. This interrupt disabling and NMI
masking should be done before *any* access to the RTC/CMOS RAM *or* the
Extended CMOS RAM. After completing the desired operations to read/write
RTC/CMOS and/or Extended CMOS RAM, restore the NMI mask by writing the
"saved" value to 70h, immediately before restoring the IE flag state.
I would recommend using PUSHF to save the IE flag's current state, followed
by CLI to disable hardware interrupts and POPF to restore (perhaps
re-enable) the original IE flag's state. That way you're not inadvertently
enabling interrupts when they might not have been before.
So we have...
Preamble:
PUSHF ;Save IE state
CLI ;Disable HW interrupts
IN AL,70h ;Get NMI mask
OUT 4Fh,AL ;I/O delay
PUSH AX ;Save NMI mask
OR AL,80h ;Mask NMI
OUT 70h,AL ;Write NMI mask
OUT 4Fh,AL ;I/O delay
IN AL,71h ;Ensure RTC/CMOS operation integrity
Postamble:
POP AX ;Restore NMI Mask
OUT 70h,AL ;(Un-)Mask NMI
OUT 4Fh,AL ;I/O Delay
IN AL,71h ;Ensure RTC/CMOS operation integrity
POPF ;Restore IE state
> I should also remember to add wait steps for back-to-back I/O port
> accesses in the fast Assembler routines. Sloppy thinking on my part not
> adding them so far. You can get by a million times, but the first time it
> falls through a hole because it is missing a couple bytes of code...
The ideal "delay" to use has changed from the "JMP $+2" recommended by the
early PS/2 HITR, to "OUT 4Fh,AL" [outp(4Fh,xx), where xx = anything, say
0FFh]. Note that port 4Fh is deemed to be a "never decoded" I/O address.
This "spurious" I/O causes I/O-buffering CPUs to flush any pending I/Os and
also provides sufficient delay between I/O operations to the same or related
ports i.e. "back-to-back I/O".
> > Also, the "address register pair" 74h (low byte) and 75h
> > (high byte) should be set back to 0186h before leaving
> > this section.
Above corrected.
> > Same for RTC/CMOS as regards "interrupts
> > disabled" and which should be left pointing to 1Eh.
Whoops, that's for POST routines, for "normal operation" RTC/CMOS should be
left pointing to 0Dh (Valid Ram Status) as noted in the HITR Supplements for
each system.
> Don't you mean 75h (high byte) and 74h (low byte)?
Yeah, my mistake, I noticed it earlier but didn't get chance to correct
myself.
> Register 76h is for retrieving the value of the Extended CMOS location
> pointed to by registers 75h & 74h.
> Why 0186h? Because that is an unassigned byte that is used to
> check if the MCA Extended CMOS exists by writing, then reading, a value to
> that location.
No, that's not its function. It is the "Extended CMOS Validity" byte. If
non-zero, either power was lost (80h bit on) or a checksum error occurred on
some section of its contents (40h bit on, possibly others). This is similar
in use to the RTC/CMOS "Status Byte 0Eh", at least for the top two bits.
> I don't have this done in my routines, but will modify them
> as soon as I can.
> I recommend a book like "Undocumented PC" for programmers that choose
to
> bypass the BIOS routines & write/read directly to the RTC/CMOS chip. My
> individual results were errors up to 10% of the time if not carefully
> programmed!
That really applies only to messing with RTC/CMOS "registers" 00-0Ch, but
leaving interrupts disabled for too long (more than 18.2ms) in *any* routine
*will* cause clock "drift" never mind any clock values read to be off from
the "current" values.
> The reason for this is during a clock update cycle all chip
> registers can be inaccessable. This doesn't hold as true for the Extended
> CMOS chip, since it is normally separate from the RTC functions.
Yes, well, see my expanded and corrected information above.
--
Cheers,
Tim