# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# i8254/i82.c
# i8254/i82.doc
# i8254/isa.h
# i8254/isa_bus.s
# i8254/notes
# i8254/osdepend.h
# i8254/timer.h
#
echo x - i8254/i82.c
sed 's/^X//' >i8254/i82.c << 'END-of-i8254/i82.c'
X/*
X Test of the Intel 8254 shut-down/parity-check command
X
X*/
X
X/* Internal Documentation */
X#define TEST_TYPE "shut-down/parity-check"
X#define PROGRAM_VERSION "version 1.0.0"
X
X/* identify OS and compiler maker */
X#define COMPILER __ZTC__
X
X/* standard headers */
X#include <stdio.h> /* Standard Input/Ouput */
X#include <stdlib.h> /* Standard Library */
X#include <stddef.h> /* Standard Definitions for ANSI C */
X
X/* alias for readablity */
X#define u_char unsigned char /* alias */
X#define u_short u_char /* another alias */
X
X/* stuff to fiddle with */
X#define SHORT_COUNT 10 /* count-down time for timer */
X#define DEBUG 0 /* Debugging aids ON=1/OFF=0 */
X#define SHOW_IT(x) printf(#x" %02x\n",x)
X
X/* local headers (same directory) */
X#include "osdepend.h" /* OS Dependent routines and variables */
X#include "timer.h" /* Constants for Intel 8254 timer */
X
X/* //////////////////////////////////////////////////
X
X Program constants
X
X*/
X#define START_INTERNAL "INTERNAL NOTES: "
X#define END_INTERNAL "END INTERNAL NOTES!!!"
X#define AUTHOR "
[email protected]"
X#define MAINTAINER AUTHOR
X#define FILENAME "Filename:"
X#define CHIP_IN_TEST "Intel 8254"
X#define COMPILE_TimeDate "compile time & date:"
X
X/* Internal documentation to executable */
Xstatic u_char *compile_info[8] = { (u_char *) START_INTERNAL,
X (u_char *) AUTHOR"; ",
X (u_char *) FILENAME" "__FILE__,
X (u_char *) CHIP_IN_TEST"; ",
X (u_char *) TEST_TYPE" "PROGRAM_VERSION"; ",
X (u_char *) COMPILE_TimeDate" " __TIME__" ",
X (u_char *) __DATE__ , /* stamps todays date */
X (u_char *) END_INTERNAL
X };
X
X/* //////////////////////////////////////////////////
X
X M A I N
X
X*/
Xmain (int argc,char **argv)
X{
X u_char scratch,temp;
X int offset;
X
X
X printf(" Test of the "CHIP_IN_TEST" "TEST_TYPE" for the "OS_STRG"\n");
X printf(" Report errors to "MAINTAINER"\n");
X
X /* Don't shut down the time of day so parity will error */
X for (offset = TIMER1_COUNTER1; offset < TIMER1_COUNTER2 + 1; offset++) {
X
X /* Set control mode to software retriggerable */
X /* Set read/write to LSB then MSB */
X /* and Identify counter */
X scratch = CNTLR_MODE4 | CNTRL_RW_LSB_MSB | (CNTRL_WRD_COUNTER0 << offset);
X
X #if DEBUG
X SHOW_IT(scratch);
X #endif
X
X /* issue command */
X outb(TIMER1_BASE_ADDR + TIMER1_CNTRL_WORD, scratch);
X
X /* write LSB */
X outb(TIMER1_BASE_ADDR + offset, SHORT_COUNT);
X
X /* write MSB */
X outb(TIMER1_BASE_ADDR + offset, SHORT_COUNT);
X
X }
X
X printf(" ************ ENDS RESET ************\n");
X printf(" READ-BACK COMMAND REPORTS\n");
X
X for (offset = TIMER1_COUNTER0; offset < TIMER1_COUNTER2 + 1; offset++) {
X
X /* identify readback command parameters */
X scratch = CMD_READBACK | (CMD_COUNTER0 << offset);
X
X #if DEBUG
X SHOW_IT(scratch);
X #endif
X
X /* issue command */
X outb(TIMER1_BASE_ADDR + TIMER1_CNTRL_WORD, scratch);
X
X /* get back status */
X scratch = inb(TIMER1_BASE_ADDR + offset);
X
X /* report results */
X printf("\n Timer channel %i reports %2x\n", offset, scratch);
X
X
X /* report OUT pin and Null count */
X if (scratch & STAT_OUTPUT_HI)
X printf(" The OUT pin is high.\n");
X if (scratch & STAT_NULL_COUNT)
X printf(" Null count is returned.\n");
X
X
X /* should return a value 1..6 */
X temp = ((scratch & CNTRL_MODE_MASK) >> 1);
X printf(" Control mode is %4x; ", temp);
X
X
X /* report if counting in BSD or binary mode */
X temp = (scratch & CNTRL_NUM_MASK);
X printf("counting in %s.\n", (temp) ? "bcd":"binary");
X
X /* read/write is lsb, msb or "lsb then msb" */
X printf(" Read/Write format is ");
X switch (scratch & CNTRL_RW_MASK) {
X case CNTRL_RW_LSB_MSB:
X printf("LSB_MSB");
X scratch = inb(TIMER1_BASE_ADDR + offset);
X temp = inb(TIMER1_BASE_ADDR + offset);
X printf(" %#02x%02x", scratch, temp);
X break;
X case CNTRL_RW_MSB:
X printf("MSB");
X scratch = inb(TIMER1_BASE_ADDR + offset);
X printf(" %#02x", scratch);
X break;
X case CNTRL_RW_LSB:
X printf("LSB") ;
X scratch = inb(TIMER1_BASE_ADDR + offset);
X printf(" %#02x", scratch);
X break;
X }
X printf("\n");
X
X }
X printf(" ************ ENDS REPORTS ************\n");
X
X}
X
X
END-of-i8254/i82.c
echo x - i8254/i82.doc
sed 's/^X//' >i8254/i82.doc << 'END-of-i8254/i82.doc'
X
X
X Test of the Intel 8254 shut-down/parity-check command
X -----------------------------------------------------
X
Xversion: 1.0.0
Xdate: 09-14-1993
Xauthor:
[email protected]
X
X Purpose: Test the for parity errors by shutting down
X the RAM refresh timer.
X
X While looking for the reason for DMA overruns
X in the development of an FDC driver for
X 386bsd, suggestions were made that shutting
X down the timer has no effect on the system;
X reasons for this varied.
X
X Compiling: I have made the code transportable.
X It has been tested with:
X
X MSDOS
X -----
X Zortech Personal C v. 1.07
X Turbo C v. 2.01
X Microsoft Quick C v. 2.50
X
X 386BSD
X ------
X GNU C++ v. 1.39
X
X
X
X How this works.
X ---------------
X Simply the program issue a command to change
X to mode 4 (described in the notes) with a "count-down"
X value of 0x0a0a (2,570). This is done to timers 1 and 2,
X the RAM refresh timer and the speaker timer, respectively.
X Timer 0 is left running because most OSes cannot operate
X without a timer for the "deadloop".
X
X
X What should happen.
X -------------------
X On most 286 systems nothing will happen till a
X interrupt is generated (I.E., keyboard pressed) or a RAM
X chip finally loses it's charge. At this point, some system
X will hang for a long while, some will immediately parity
X error.
X On 386bsd expect a "csh" coredump followed by a
X system panic. The system will then reboot. On some systems
X a parity error will never register.
X
X
X What does this prove?
X ---------------------
X Namely that the RAM refresh is controllable via
X the i8254 timer on the IBM/ISA architecture.
X
X
X WARNING WARNING WARNING WARNING
X WARNING WARNING WARNING WARNING
X WARNING WARNING WARNING WARNING
X ------- ------- ------- -------
X
X To get your system back in working order you will
X have to do a "cold boot". This means the RAM has to be
X recounted. The equivalent is hit the red button on the
X front of the computer _or_ if you don't have one -- turn
X your machine off, then on (don't forget to count to 10).
X
X Also if you have a slightly flakey RAM chip this
X may be just the thing to make it fail completely. You
X have been warned.
X
X
X About 386BSD
X ------------
X For the 386bsd version it was necessary to add the
X inb() and outb() code. Even though this is in the "locore"
X section of the kernel, I do not know the exact method of adding
X it to this code.
X
X Compile as:
X
X cc -c isa_bus.s
X cc i82.c isa_bus.o
X
X
X Files included
X --------------
X i82.c Source code for the main program.
X i82.doc This file.
X isa.h Included for convience.
X timer.h Code related directly to the Intel 8254 timer.
X osdepend.h Operating System Dependent stuff.
X isa_bus.s GAS (Gnu ASsemble) code for inb() and outb().
X This file is only for 386bsd.
X notes My notes for the Intel 8254 from various
X sources.
X
X
X ERRORS, PROBLEMS or QUESTIONS
X -----------------------------
X
X To reach me send e-mail to
[email protected]
X
END-of-i8254/i82.doc
echo x - i8254/isa.h
sed 's/^X//' >i8254/isa.h << 'END-of-i8254/isa.h'
X/*-
X * Copyright (c) 1990 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * William Jolitz.
X *
X * @(#)isa.h 5.7 (Berkeley) 5/9/91
X */
X
X/*
X * ISA Bus conventions
X */
X
X#ifndef LOCORE
Xunsigned char inb(), rtcin();
Xvoid outb();
Xextern unsigned int atdevbase; /* offset in virtual memory of ISA io mem */
Xvoid sysbeep(int,int);
Xunsigned kbd_8042cmd(int);
X#endif
X
X
X/*
X * Input / Output Port Assignments
X */
X
X#ifndef IO_BEGIN
X#define IO_ISABEGIN 0x000 /* 0x000 - Beginning of I/O Registers */
X
X /* CPU Board */
X#define IO_DMA1 0x000 /* 8237A DMA Controller #1 */
X#define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */
X#define IO_TIMER1 0x040 /* 8252 Timer #1 */
X#define IO_TIMER2 0x048 /* 8252 Timer #2 */
X#define IO_KBD 0x060 /* 8042 Keyboard */
X#define IO_RTC 0x070 /* RTC */
X#define IO_NMI IO_RTC /* NMI Control */
X#define IO_DMAPG 0x080 /* DMA Page Registers */
X#define IO_ICU2 0x0A0 /* 8259A Interrupt Controller #2 */
X#define IO_DMA2 0x0C0 /* 8237A DMA Controller #2 */
X#define IO_NPX 0x0F0 /* Numeric Coprocessor */
X
X /* Cards */
X /* 0x100 - 0x16F Open */
X
X#define IO_WD2 0x170 /* Secondary Fixed Disk Controller */
X
X /* 0x178 - 0x1EF Open */
X
X#define IO_WD1 0x1f0 /* Primary Fixed Disk Controller */
X#define IO_GAME 0x200 /* Game Controller */
X
X /* 0x208 - 0x277 Open */
X
X#define IO_LPT2 0x278 /* Parallel Port #2 */
X
X /* 0x280 - 0x2F7 Open */
X
X#define IO_COM2 0x2f8 /* COM2 i/o address */
X
X /* 0x300 - 0x36F Open */
X
X#define IO_FD2 0x370 /* secondary base i/o address */
X#define IO_LPT1 0x378 /* Parallel Port #1 */
X
X /* 0x380 - 0x3AF Open */
X
X#define IO_MDA 0x3B0 /* Monochome Adapter */
X#define IO_LPT3 0x3BC /* Monochome Adapter Printer Port */
X#define IO_VGA 0x3C0 /* E/VGA Ports */
X#define IO_CGA 0x3D0 /* CGA Ports */
X
X /* 0x3E0 - 0x3EF Open */
X
X#define IO_FD1 0x3f0 /* primary base i/o address */
X#define IO_COM1 0x3f8 /* COM1 i/o address */
X
X#define IO_ISAEND 0x3FF /* - 0x3FF End of I/O Registers */
X#endif IO_ISABEGIN
X
X/*
X * Input / Output Memory Physical Addresses
X */
X
X#ifndef IOM_BEGIN
X#define IOM_BEGIN 0x0a0000 /* Start of I/O Memory "hole" */
X#define IOM_END 0x100000 /* End of I/O Memory "hole" */
X#define IOM_SIZE (IOM_END - IOM_BEGIN)
X#endif IOM_BEGIN
X
X/*
X * RAM Physical Address Space (ignoring the above mentioned "hole")
X */
X
X#ifndef RAM_BEGIN
X#define RAM_BEGIN 0x0000000 /* Start of RAM Memory */
X#define RAM_END 0x1000000 /* End of RAM Memory */
X#define RAM_SIZE (RAM_END - RAM_BEGIN)
X#endif RAM_BEGIN
X
X/*
X * Oddball Physical Memory Addresses
X */
X#ifndef COMPAQ_RAMRELOC
X#define COMPAQ_RAMRELOC 0x80c00000 /* Compaq RAM relocation/diag */
X#define COMPAQ_RAMSETUP 0x80c00002 /* Compaq RAM setup */
X#define WEITEK_FPU 0xC0000000 /* WTL 2167 */
X#define CYRIX_EMC 0xC0000000 /* Cyrix EMC */
X#endif COMPAQ_RAMRELOC
END-of-i8254/isa.h
echo x - i8254/isa_bus.s
sed 's/^X//' >i8254/isa_bus.s << 'END-of-i8254/isa_bus.s'
X /*
X * I/O bus instructions via C
X */
X .globl _inb
X_inb: movl 4(%esp),%edx
X subl %eax,%eax # clr eax
X NOP
X inb %dx,%al
X ret
X
X
X .globl _inw
X_inw: movl 4(%esp),%edx
X subl %eax,%eax # clr eax
X NOP
X inw %dx,%ax
X ret
X
X
X .globl _rtcin
X_rtcin: movl 4(%esp),%eax
X outb %al,$0x70
X subl %eax,%eax # clr eax
X inb $0x71,%al # Compaq SystemPro
X ret
X
X .globl _outb
X_outb: movl 4(%esp),%edx
X NOP
X movl 8(%esp),%eax
X outb %al,%dx
X NOP
X ret
X
X .globl _outw
X_outw: movl 4(%esp),%edx
X NOP
X movl 8(%esp),%eax
X outw %ax,%dx
X NOP
X ret
X
END-of-i8254/isa_bus.s
echo x - i8254/notes
sed 's/^X//' >i8254/notes << 'END-of-i8254/notes'
X
XNotes to the i8254 timer chip.
X
X From: IBM Personal Computer Troubleshooting & Repair
X for the IBM PC, PC/XT, and PC AT; by Robert C. Brenner
X Pub. Howard W. Sams & Company
X
X pg. 106
X timer 0 (zero) produces the time-of-day irq at 18.2 times/sec.
X timer 1 produces the RAM refresh at 66,287 times/sec.
X timer 2 is varied for the speaker driver.
X
X pg. 122
X Out1 occurs every 15usec (microseconds).
X Note: Out1 is directly tied to timer 1.
X
X From: 1988 Intel Microprocessor and Peripherial Handbook, vol.2
X
X pg. 2-34
X Mode 2: Rate Generator (condensed)
X The mode functions like a divide-by-N counter.
X OUT will initially be high. When the initial count
X has decremented to 1, OUT goes low for one CLK pulse.
X OUT goes high again, the Counter reloads the initial
X count and the process is repeated. Mode 2 is
X periodic; the same sequence is repeated indefinitely.
X
X (Read book/section for programming specifics.)
X Note: A count (N) of 1 is illegal.
X
X pg. 2-39
X Mode 4: Software Triggered Strobe (condensed)
X OUT will be initially high. When the initial count
X expires, OUT will go low for one CLK pulse and then go
X high again. The counting sequence is "triggered" by
X writting the initial count.
X
X OUT will not go low again until a new count is loaded;
X this then is the software "trigger", allowing OUT to
X go low when the count terminates again.
X
X (Read book/section for programming specifics.)
X Note: OUT does not strobe low until N+1 CLK pulses
X after the initial count is written.
X
X
END-of-i8254/notes
echo x - i8254/osdepend.h
sed 's/^X//' >i8254/osdepend.h << 'END-of-i8254/osdepend.h'
X/*
X
X functions as dependent on OS and Compiler
X*/
X#if (MSDOS)
X
X #define OS_STRG "MSDOS"
X #define TIMER1_BASE_ADDR 0x40 /* IO_TIMER1 for 386bsd*/
X
X #if (COMPILER == __ZTC__) /* Zortech Personal C */
X
X #include <dos.h>
X #define outb(addr,var) outp(addr,var)
X #define inb(addr) inp(addr)
X
X #elif (COMPILER == __TC__) /* Borland Turbo C */
X
X #include <dos.h>
X #define outb(addr,var) outportb(addr,var)
X #define inb(addr) inportb(addr)
X
X #elif (COMPILER == __MSC__) /* Microsoft Quick C */
X
X #include <conio.h>
X #define outb(addr,var) outp(addr,var)
X #define inb(addr) inp(addr)
X #endif
X
X#else /* assume 386BSD and GNU C++ */
X #include "isa.h"
X #define OS_STRG "386BSD"
X #define TIMER1_BASE_ADDR IO_TIMER1
X#endif
X
X
END-of-i8254/osdepend.h
echo x - i8254/timer.h
sed 's/^X//' >i8254/timer.h << 'END-of-i8254/timer.h'
X/* /////////////////////////////////////////////
X
X Some defines for the Intel 8254 PIT (Programable Interrupt Timer)
X
X*/
X/* /////////////////////////////////////////////
X
X I/O Address and offsets to registers.
X
X*/
X#define TIMER1_COUNTER0 0 /* Offset to counter 0 */
X#define TIMER1_COUNTER1 1 /* Offset to counter 1 */
X#define TIMER1_COUNTER2 2 /* Offset to counter 2 */
X#define TIMER1_CNTRL_WORD 3 /* Offset to Control Register */
X
X/* /////////////////////////////////////////////
X
X Control Word Format
X
X See data guides for how the modes work.
X Note: Except for the READBACK command,
X only one counter can be programed
X at a time.
X*/
X
X#define CNTRL_WRD_READBACK 0xC0 /* 1100 0000 */
X#define CNTRL_WRD_COUNTER2 0x80 /* control applies to this register, if high */
X#define CNTRL_WRD_COUNTER1 0x40 /* control applies to this register, if high */
X#define CNTRL_WRD_COUNTER0 0x20 /* control applies to this register, if high */
X#define CNTRL_COUNTER_LATCH 0X00 /* bits 5 & 4 must be zero */
X#define CNTRL_RW_LSB_MSB 0x30 /* read/write to counter register is LSB then MSB */
X#define CNTRL_RW_MSB 0x20 /* read/write to counter register is MSB */
X#define CNTRL_RW_LSB 0x10 /* read/write to counter register is LSB */
X#define CNTLR_MODE5 0x0A /* 1 << 5 */
X#define CNTLR_MODE4 0x08 /* 1 << 4 */
X#define CNTLR_MODE3 0x06 /* 1 << 3 */
X#define CNTLR_MODE2 0x04 /* 1 << 2 */
X#define CNTLR_MODE1 0x02 /* 1 << 1 */
X#define CNTLR_MODE0 0x00 /* 1 << 0; bit 1 must be low */
X#define CNTRL_DO_BCD 0x01 /* count as Binary Coded Decimal */
X#define CNTRL_DO_BIN 0x00 /* bit 0 must be low for Binary counting */
X
X/* Alias Logic Masks for readablity */
X#define CNTRL_RW_MASK CNTRL_RW_LSB_MSB
X#define CNTRL_MODE_MASK 0x0E /* Look at high 3 bits in nibble */
X#define CNTRL_NUM_MASK CNTRL_DO_BCD
X
X
X/* /////////////////////////////////////////////
X
X Command Format
X
X Issuing the correct bits will return the program
X mode and "latched" count of the counter, in the
X respective counter register.
X
X*/
X#define CMD_READBACK CNTRL_WRD_READBACK /* without this - the command does not happen */
X#define CMD_NO_LATCH_COUNT 0x20 /* don't latch the current timer value */
X#define CMD_NO_LATCH_STAT 0x10 /* don't latch the current status value */
X#define CMD_COUNTER2 0x08 /* this command applies to this register, if bit high */
X#define CMD_COUNTER1 0x04 /* same as above */
X#define CMD_COUNTER0 0x02 /* same as above */
X#define CMD_RESERVE 0x01 /* don't use this bit */
X
X/*
X
X Status Register Format
X
X After issuing a ""readback"" command the status
X information comes back in the format below.
X The lower 6 bits follow the Control Word Format.
X
X*/
X#define STAT_OUTPUT_HI 0x80 /* The OUT pin is High */
X#define STAT_NULL_COUNT 0x40 /* currently a null count hit on the counter */
X
END-of-i8254/timer.h
exit