/*********************************************************************** * * lpMode.c * Tom Kelliher * Jan. 19, 2000 * * Copyright (C) 2000 Thomas P. Kelliher, Goucher College * * Determine the mode of a parallel port in Linux. By default, the * parallel port at 0x378 is used. * * The "algorithms" are documented in "Parallel Port Complete" by Jan * Axelson, Lakeview Research, 1999. * * WARNING: IT IS YOUR RESPONSIBILITY TO ENSURE THAT HOST DATA LINE * DRIVERS AND PERIPHERAL DATA LINE DRIVERS ARE NOT SIMULTANEOUSLY * ENABLED. Ignoring this warning may result in damage to the host, * the peripheral, and your wallet. * * Compiling note: You must use gcc's "-O" switch. * * Running notes: * This program must run with root privileges. * ***********************************************************************/ #include #include #include #include /* printer port base address. other possibilities: 0x278, 0x3bc */ #define BASE 0x378 /* Offsets of various mode's registers */ #define STATUS 1 #define CONTROL 2 #define EPA 3 #define ECR 0x402 /* function prototypes */ int ecpTest(int base); int eppTest(int base); void clearEppTimeoutBit(int base); int sppTest(int base); int ps2Test(int base); /*********************************************************************** * * main() * ***********************************************************************/ int main() { /* try to get the entire I/O space */ if (iopl(3)) { printf("Couldn't get the port addresses.\n"); return 1; } if (ecpTest(BASE)) printf("ECP parallel port\n"); else if (eppTest(BASE)) printf("EPP parallel port\n"); else if (sppTest(BASE)) if (ps2Test(BASE)) printf("PS/2 parallel port\n"); else printf("SPP parallel port\n"); else printf("No parallel port\n"); return 0; } /*********************************************************************** * * ecpTest() * * Determine if there is an ECP port at base. * * Returns 1 if an ECP port is found, otherwise 0. The state of the * port is restored upon exit. * ***********************************************************************/ int ecpTest(int base) { unsigned char ecr; /* ECP control register */ unsigned char ecrOrig; /* original value */ unsigned char control; /* control register */ unsigned char controlOrig; /* original value */ ecr = ecrOrig = inb(base + ECR); /* ecr bit 0 should be 1 and ecr bit 1 should be 0 */ if ((ecr & 3) != 1) return 0; /* check that ecr bits 0 and 1 are independent of control bits */ /* 0 and 1 */ control = controlOrig = inb(base + CONTROL); /* if control and ecr bits happen to have the same value, toggle */ /* a control bit and check an ecr bit */ if (!(control & 2)) { outb(3, base + CONTROL); ecr = inb(base + ECR); outb(controlOrig, base + CONTROL); if (ecr & 2) return 0; } /* write 0x34 to ecr. value read back should be 0x35. */ outb(0x34, base + ECR); ecr = inb(base + ECR); outb(ecrOrig, base + ECR); return ecr == 0x35; } /*********************************************************************** * * eppTest() * * Determine if there is an EPP port at base. * * Returns 1 if an EPP port is found, otherwise 0. The state of the * port is restored upon exit. * ***********************************************************************/ int eppTest(int base) { unsigned char epa; /* EPP address register */ unsigned char epaOrig; /* original value */ unsigned char statusOrig; /* status register original value */ /* parallel port at 0x3bc can't be in EPP mode because of I/O space */ /* conflicts */ if (base == 0x3bc) return 0; epaOrig = inb(base + EPA); statusOrig = inb(base + STATUS); /* try to write and read two values to/from EPP address port */ outb(0x55, base + EPA); clearEppTimeoutBit(base); /* operations will timeout, so clear */ epa = inb(base + EPA); clearEppTimeoutBit(base); if (epa != 0x55) { outb(epaOrig, base + EPA); clearEppTimeoutBit(base); outb(statusOrig, base + STATUS); return 0; } outb(0xaa, base + EPA); clearEppTimeoutBit(base); epa = inb(base + EPA); clearEppTimeoutBit(base); outb(epaOrig, base + EPA); clearEppTimeoutBit(base); outb(statusOrig, base + STATUS); return epa == 0xaa; } /*********************************************************************** * * clearEppTimeoutBit() * * Clear the timeout bit of the alleged EPP port at base. * ***********************************************************************/ void clearEppTimeoutBit(int base) { inb(base + STATUS); outb(1, base + STATUS); outb(0, base + STATUS); inb(base + STATUS); } /*********************************************************************** * * sppTest() * * Determine if there is an SPP port at base. * * Returns 1 if an SPP port is found, otherwise 0. The state of the * port is restored upon exit. * ***********************************************************************/ int sppTest(int base) { unsigned char data; /* data register */ unsigned char dataOrig; /* original value */ unsigned char controlOrig; /* control register original value */ dataOrig = inb(base); controlOrig = inb(base + CONTROL); /* enable data outputs */ outb(0xf, base + CONTROL); /* attempt to write and read two values */ outb(0x55, base); data = inb(base); if (data != 0x55) { outb(dataOrig, base); outb(controlOrig, base + CONTROL); return 0; } outb(0xaa, base); data = inb(base); outb(dataOrig, base); outb(controlOrig, base + CONTROL); return data == 0xaa; } /*********************************************************************** * * ps2Test() * * Determine if there is an PS/2 port at base. * * Returns 1 if a PS/2 port is found, otherwise 0. The state of the * port is restored upon exit. * ***********************************************************************/ int ps2Test(int base) { unsigned char data; /* data register */ unsigned char dataOrig; /* original value */ unsigned char controlOrig; /* control register original value */ dataOrig = inb(base); controlOrig = inb(base + CONTROL); /* disable data outputs */ outb(0x2f, base + CONTROL); /* if the port is bidirectional, we shouldn't read what we wrote, */ /* unless the driving side happens to have the same value. in */ /* this case, write a second value and read again */ outb(0x55, base); data = inb(base); if (data != 0x55) { outb(dataOrig, base); outb(controlOrig, base + CONTROL); return 1; } outb(0xaa, base); data = inb(base); outb(dataOrig, base); outb(controlOrig, base + CONTROL); return data != 0xaa; }