From 4a8f8b25016858b241cf5ea1551a3979cb2e7bd5 Mon Sep 17 00:00:00 2001 From: jmg Date: Fri, 19 Sep 1997 15:36:00 +0000 Subject: this is an import of Sujal M. Petal's pnpinfo.. it includes modifications by Luigi Rizzo and myself... --- contrib/pnpinfo/pnpinfo.c | 607 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 607 insertions(+) create mode 100644 contrib/pnpinfo/pnpinfo.c (limited to 'contrib/pnpinfo/pnpinfo.c') diff --git a/contrib/pnpinfo/pnpinfo.c b/contrib/pnpinfo/pnpinfo.c new file mode 100644 index 0000000..6a804fd --- /dev/null +++ b/contrib/pnpinfo/pnpinfo.c @@ -0,0 +1,607 @@ +/* + * Copyright (c) 1996, Sujal M. Patel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: pnpinfo.c,v 1.16 1996/05/05 23:56:38 smpatel Exp $ + */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif +#define DDB(x) x + +void +pnp_write(int d, u_char r) +{ + outb (_PNP_ADDRESS, d); + outb (_PNP_WRITE_DATA, r); +} +/* The READ_DATA port that we are using currently */ +static int rd_port; + +u_char +pnp_read(int d) +{ + outb(_PNP_ADDRESS, d); + return inb( (rd_port << 2) + 3) & 0xff; +} + +u_char +pnp_readw(int d) +{ + int c = pnp_read(d) << 8 ; + c |= pnp_read(d+1); + return c; +} + +int logdevs=0; + +void DELAY __P((int i)); +void send_Initiation_LFSR(); +int get_serial __P((u_char *data)); +int get_resource_info __P((u_char *buffer, int len)); +int handle_small_res __P((u_char *resinfo, int item, int len)); +void handle_large_res __P((u_char *resinfo, int item, int len)); +void dump_resdata __P((u_char *data, int csn)); +int isolation_protocol(); + + +/* + * DELAY does accurate delaying in user-space. + * This function busy-waits. + */ +void +DELAY (int i) +{ + struct timeval t; + long start, stop; + + i *= 4; + + gettimeofday (&t, NULL); + start = t.tv_sec * 1000000 + t.tv_usec; + do { + gettimeofday (&t, NULL); + stop = t.tv_sec * 1000000 + t.tv_usec; + } while (start + i > stop); +} + + +/* + * Send Initiation LFSR as described in "Plug and Play ISA Specification, + * Intel May 94." + */ +void +send_Initiation_LFSR() +{ + int cur, i; + + pnp_write(CONFIG_CONTROL, 0x2); + + /* Reset the LSFR */ + outb(_PNP_ADDRESS, 0); + outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */ + + cur = 0x6a; + + for (i = 0; i < 32; i++) { + outb(_PNP_ADDRESS, cur); + cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff); + } +} + +/* + * Get the device's serial number. Returns 1 if the serial is valid. + */ +int +get_serial(u_char *data) +{ + int i, bit, valid = 0, sum = 0x6a; + + bzero(data, sizeof(char) * 9); + + for (i = 0; i < 72; i++) { + bit = inb((rd_port << 2) | 0x3) == 0x55; + DELAY(250); /* Delay 250 usec */ + + /* Can't Short Circuit the next evaluation, so 'and' is last */ + bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit; + DELAY(250); /* Delay 250 usec */ + + valid = valid || bit; + + if (i < 64) + sum = (sum >> 1) | + (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff); + + data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0); + } + + valid = valid && (data[8] == sum); + + return valid; +} + + +/* + * Fill's the buffer with resource info from the device. + * Returns 0 if the device fails to report + */ +int +get_resource_info(u_char *buffer, int len) +{ + int i, j; + + for (i = 0; i < len; i++) { + outb(_PNP_ADDRESS, STATUS); + for (j = 0; j < 100; j++) { + if ((inb((rd_port << 2) | 0x3)) & 0x1) + break; + DELAY(1); + } + if (j == 100) { + printf("PnP device failed to report resource data\n"); + return 0; + } + outb(_PNP_ADDRESS, RESOURCE_DATA); + buffer[i] = inb((rd_port << 2) | 0x3); + DEB(printf("--- get_resource_info: got 0x%02x\n",(unsigned)buffer[i])); + } + return 1; +} + +void +report_dma_info (x) + int x; +{ + char *s1=NULL, *s2=NULL, *s3=NULL, *s4=NULL, *s5=NULL; + + switch (x & 0x3) { + case 0: + s1="8-bit"; + break; + case 1: + s1="8/16-bit"; + break; + case 2: + s1="16-bit"; + break; +#ifdef DIAGNOSTIC + case 3: + s1="Reserved"; + break; +#endif + } + + s2 = (x & 0x4) ? "bus master" : "not a bus master"; + + s3 = (x & 0x8) ? "count by byte" : ""; + + s4 = (x & 0x10) ? "count by word" : ""; + + switch ((x & 0x60) >> 5) { + case 0: + s5="Compatibility mode"; + break; + case 1: + s5="Type A"; + break; + case 2: + s5="Type B"; + break; + case 3: + s5="Type F"; + break; + } + printf("\t%s, %s, %s, %s, %s\n",s1,s2,s3,s4,s5); +} + + +void +report_memory_info (int x) +{ + if (x & 0x1) + printf ("Memory Range: Writeable\n"); + else + printf ("Memory Range: Not writeable (ROM)\n"); + + if (x & 0x2) + printf ("Memory Range: Read-cacheable, write-through\n"); + else + printf ("Memory Range: Non-cacheable\n"); + + if (x & 0x4) + printf ("Memory Range: Decode supports high address\n"); + else + printf ("Memory Range: Decode supports range length\n"); + + switch ((x & 0x18) >> 3) { + case 0: + printf ("Memory Range: 8-bit memory only\n"); + break; + case 1: + printf ("Memory Range: 16-bit memory only\n"); + break; + case 2: + printf ("Memory Range: 8-bit and 16-bit memory supported\n"); + break; +#ifdef DIAGNOSTIC + case 3: + printf ("Memory Range: Reserved\n"); + break; +#endif + } + + if (x & 0x20) + printf ("Memory Range: Memory is shadowable\n"); + else + printf ("Memory Range: Memory is not shadowable\n"); + + if (x & 0x40) + printf ("Memory Range: Memory is an expansion ROM\n"); + else + printf ("Memory Range: Memory is not an expansion ROM\n"); + +#ifdef DIAGNOSTIC + if (x & 0x80) + printf ("Memory Range: Reserved (Device is brain-damaged)\n"); +#endif +} + + +/* + * Small Resource Tag Handler + * + * Returns 1 if checksum was valid (and an END_TAG was received). + * Returns -1 if checksum was invalid (and an END_TAG was received). + * Returns 0 for other tags. + */ +int +handle_small_res(u_char *resinfo, int item, int len) +{ + int i; + + DEB(printf("*** ITEM 0x%04x len %d detected\n", item, len)); + + switch (item) { + default: + printf("*** ITEM 0x%02x detected\n", item); + break; + case PNP_VERSION: + printf("PnP Version %d.%d, Vendor Version %d\n", + resinfo[0] >> 4, resinfo[0] & (0xf), resinfo[1]); + break; + case LOG_DEVICE_ID: + printf("\nLogical Device ID: %c%c%c%02x%02x 0x%08x #%d\n", + ((resinfo[0] & 0x7c) >> 2) + 64, + (((resinfo[0] & 0x03) << 3) | + ((resinfo[1] & 0xe0) >> 5)) + 64, + (resinfo[1] & 0x1f) + 64, + resinfo[2], resinfo[3], *(int *)(resinfo), + logdevs++); + + if (resinfo[4] & 0x1) + printf ("\tDevice powers up active\n"); /* XXX */ + if (resinfo[4] & 0x2) + printf ("\tDevice supports I/O Range Check\n"); + if (resinfo[4] > 0x3) + printf ("\tReserved register funcs %02x\n", + resinfo[4]); + + if (len == 6) + printf("\tVendor register funcs %02x\n", resinfo[5]); + break; + case COMP_DEVICE_ID: + printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n", + ((resinfo[0] & 0x7c) >> 2) + 64, + (((resinfo[0] & 0x03) << 3) | + ((resinfo[1] & 0xe0) >> 5)) + 64, + (resinfo[1] & 0x1f) + 64, + resinfo[2], resinfo[3], *(int *)resinfo); + break; + case IRQ_FORMAT: + printf(" IRQ: "); + + for (i = 0; i < 8; i++) + if (resinfo[0] & (1<> 2) + 64, + (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64, + (data[1] & 0x1f) + 64, data[2], data[3], + *(int *)&(data[0]), + *(int *)&(data[4])); + + pnp_write(SET_CSN, csn); /* Move this out of this function XXX */ + outb(_PNP_ADDRESS, STATUS); + + /* Allows up to 1kb of Resource Info, Should be plenty */ + for (i = 0; i < 1024; i++) { + if (!get_resource_info(&tag, 1)) + break; + +#define TYPE (tag >> 7) +#define S_ITEM (tag >> 3) +#define S_LEN (tag & 0x7) +#define L_ITEM (tag & 0x7f) + + if (TYPE == 0) { + /* Handle small resouce data types */ + + resinfo = malloc(S_LEN); + if (!get_resource_info(resinfo, S_LEN)) + break; + + if (handle_small_res(resinfo, S_ITEM, S_LEN) == 1) + break; + free(resinfo); + } else { + /* Handle large resouce data types */ + + if (!get_resource_info((char *) &large_len, 2)) + break; + + resinfo = malloc(large_len); + if (!get_resource_info(resinfo, large_len)) + break; + + handle_large_res(resinfo, L_ITEM, large_len); + free(resinfo); + } + } + printf("Successfully got %d resources, %d logical fdevs\n", i, + logdevs); + printf("-- card select # 0x%04x\n", pnp_read(SET_CSN)); + printf("\nCSN %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n", + ((data[0] & 0x7c) >> 2) + 64, + (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64, + (data[1] & 0x1f) + 64, data[2], data[3], + *(int *)&(data[0]), + *(int *)&(data[4])); + + for (i=0; i