
/*
 *  Dump the National Semiconductor PC87308VUL SuperI/O Configuration Registers
 *
 *  (C) Copyright 1998 by Geert Uytterhoeven
 *
 *  This program is subject to the terms and conditions of the GNU General
 *  Public License
 */


#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <asm/io.h>

#undef _IO_BASE
#define _IO_BASE	isa_io_base

#define KB      *(1024)
#define MB      *(1024*1024)
#define GB      *(1024*1024*1024)


typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;


static int io_fd = -1;
static unsigned long isa_io_base = -1;


static void open_io(void)
{
    if ((io_fd = open("/dev/mem", O_RDWR)) == -1) {
	perror("open /dev/mem");
	exit(1);
    }
}

static void close_io(void)
{
    if (io_fd != -1) {
	close(io_fd);
	io_fd = -1;
    }
}

static u32 do_mmap(u32 base, u32 size)
{
    u32 res;

    res = (u32)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, io_fd, base);
    if (res == -1) {
	fprintf(stderr, "mmap 0x%08x: %s", base, strerror(errno));
	exit(1);
    }
    return res;
}

static void do_munmap(u32 addr, u32 size)
{
    if (addr != -1)
	munmap((caddr_t)addr, size);
}


static inline void sio_write(u8 val, u8 index)
{
    outb(index, 0x15c);
    outb(val, 0x15d);
}

static inline u8 sio_read(u8 index)
{
    outb(index, 0x15c);
    return inb(0x15d);
}

static void dump_card(void)
{
    u8 t8;

    puts("\n********** Card Configuration **********\n");

    t8 = sio_read(0x21);
    printf("  Super I/O Configuration Register 1 : 0x%02x\n", t8);
    printf("    *ZWS enable                      : *ZWS is %sasserted\n",
	   t8 & 1 ? "" : "not ");
    printf("    *CSOUT-NSC-test or CS0 Pin Select: %s\n",
	   t8 & 2 ? "CS0" : "*CSOUT-NSC-test");
    printf("    Drive Mode Select                : %s\n",
	   t8 & 4 ? "PC-AT" : "PS/2");
    printf("    Reserved                         : %d\n", t8 & 8 ? 1 : 0);
    printf("    X-Bus Data Buffer Select         : %s\n",
	   t8 & 16 ? "XDB enabled" : "No XDB buffer");
    printf("    Lock Scratch Bit                 : %s\n",
	   t8 & 32 ? "Bits 7/6 are read/write" : "Bits 7/6 are read only");
    printf("    General Purpose Scratch Bit 0    : %d\n", t8 & 64 ? 1 : 0);
    printf("    General Purpose Scratch Bit 1    : %d\n", t8 & 128 ? 1 : 0);

    t8 = sio_read(0x22);
    printf("  Super I/O Configuration Register 2 : 0x%02x\n", t8);
}

static void dump_device(u_int dev, const char *name)
{
    u8 t8;

    printf("\n********** Logical device %d (%s) **********\n\n", dev, name);
    sio_write(dev, 0x07);
    t8 = sio_read(0x30);
    printf("  Activate                           : %s\n",
	   t8 & 1 ? "enabled" : "disabled");
    t8 = sio_read(0x31);
    printf("  I/O Range Check                    : %d\n", t8);
    printf("  I/O Range Check Control            : %s\n",
	   t8 & 1 ? "drive 0x00AA" : "respond with 0x0055");
    printf("  I/O Range Check Control            : %s\n",
	   t8 & 2 ? "enabled" : "disabled");
    printf("  I/O Descriptor 0 Base Address      : 0x%04x\n",
	   sio_read(0x60)<<8 | sio_read(0x61));
    printf("  I/O Descriptor 1 Base Address      : 0x%04x\n",
	   sio_read(0x62)<<8 | sio_read(0x63));
    printf("  Interrupt Request Level Select 0   : ");
    t8 = sio_read(0x70);
    if (t8) {
	printf("%d\n", t8);
	t8 = sio_read(0x71);
	printf("  Interrupt Request Type Select 0    : %d (%s, %s)\n", t8,
	       t8 & 1 ? "level" : "edge", t8 & 2 ? "high" : "low");
    } else
	puts("none");
    printf("  DMA Channel Select 0               : ");
    t8 = sio_read(0x74) & 7;
    if (t8 == 4)
	puts("none");
    else
	printf("%d\n", t8);
    printf("  DMA Channel Select 1               : ");
    t8 = sio_read(0x75) & 7;
    if (t8 == 4)
	puts("none");
    else
	printf("%d\n", t8);
}

int main(int argc, char *argv[])
{
    u8 t8;

    open_io();
    isa_io_base = do_mmap(CHRP_ISA_IO_BASE, 64 KB);

    dump_card();

    dump_device(0, "KBC/Keyboard");
    t8 = sio_read(0xf0);
    printf("  Configuration Register             : 0x%02x\n", t8);
    printf("    KBC Clock Source                 : ");
    switch ((t8>>6) & 3) {
	case 0:
	    puts("8 MHz");
	    break;
	case 1:
	    puts("12 MHz");
	    break;
	case 2:
	    puts("16 MHz");
	    break;
	default:
	    puts("reserved");
	    break;
    }

    dump_device(1, "KBC/Mouse");

    dump_device(2, "RTC and ATC");

    dump_device(3, "FDC");
    t8 = sio_read(0xf0);
    printf("  Configuration Register             : 0x%02x\n", t8);
    t8 = sio_read(0xf1);
    printf("  Drive ID Register                  : 0x%02x\n", t8);

    dump_device(4, "Parallel Port");
    t8 = sio_read(0xf0);
    printf("  Configuration Register             : 0x%02x\n", t8);

    dump_device(5, "UART2 and Infrared");
    t8 = sio_read(0xf0);
    printf("  Configuration Register             : 0x%02x\n", t8);

    dump_device(6, "UART1");
    t8 = sio_read(0xf0);
    printf("  Configuration Register             : 0x%02x\n", t8);

    dump_device(7, "GPIO Ports");

    dump_device(8, "Power Management");

    do_munmap(isa_io_base, 64 KB);
    close_io();

    exit(0);
}
