242 lines
10 KiB
Text
242 lines
10 KiB
Text
.oO Phrack 50 Oo.
|
|
|
|
Volume Seven, Issue Fifty
|
|
|
|
11 of 16
|
|
|
|
|
|
H A R D W A R E I N T E R F A C I N G F O R T H E
|
|
L I N U X O P E R A T I N G S Y S T E M
|
|
|
|
By The Professor <professr@hackerz.org>
|
|
|
|
Computer control of real world devices has been an out of reach fantasy for
|
|
most people. In the past, it has rarely been seen outside the R&D labs of
|
|
hardware design companies, universities, and a few dedicated hobbyist's
|
|
basements. It takes not only a skilled programmer, but also a person that can
|
|
design and build small circuits.
|
|
|
|
In this article, I will show you how to use a standard IBM/PC parallel
|
|
printer port to control devices, such as bells, relays, and lights. I will
|
|
also show you how to take input from devices such as DTMF decoder IC's, analog
|
|
to digital converters, and switches.
|
|
|
|
To access the I/O port, the compiled program must be either executed by root
|
|
or be suid root. This could be a potential system security hazard so be
|
|
warned. In order to grant permissions to the port, one must use the function
|
|
ioperm().
|
|
|
|
Syntax (also see the man page):
|
|
|
|
#include <unistd.h>
|
|
ioperm(BASE_ADDRESS,NUM,PERMISSION_BIT);
|
|
|
|
The first parameter is the port number to set permissions of.
|
|
The second parameter is the number of consecutive ports to set permissions of.
|
|
(i.e. if num==3, BASE_ADDRESS, BASE_ADDRESS+1, and BASE_ADDRESS+2 are set).
|
|
The third parameter is 1 to give the program permissions or 0 to remove them.
|
|
|
|
Sending and receiving data via the port is done with the commands, inb() and
|
|
outb().
|
|
|
|
Syntax:
|
|
|
|
#include <asm/io.h>
|
|
value=inb(address); (address can be BASE_ADDRESS+1 or BASE_ADDRESS+2)
|
|
outb(value,BASE_ADDRESS);
|
|
|
|
|
|
O U T P U T
|
|
|
|
Making individual output data lines of a parallel printer port "turn on" is as
|
|
simple as selecting them with a corresponding binary value. Pin 2 (D0) is the
|
|
least significant bit and pin 9 (D7) is the most significant bit. If you
|
|
wanted bits 0, 2, 3, 4, and 6 to "turn on" or go high (+5v) while leaving 1,
|
|
5, and 7 low (ground) you would first convert the binary value to decimal and
|
|
then send that value to the port. (actually, there is no reason why you can't
|
|
just send the binary value to the port)
|
|
|
|
D7 D6 D5 D4 D3 D2 D1 D0
|
|
0 1 0 1 1 1 0 1 == 1011101 == 93
|
|
|
|
outb(93,BASE_ADDRESS);
|
|
|
|
If you want all lines low or "off", you send a 0.
|
|
If you want them all high or "on", you send 255.
|
|
|
|
Controlling the status of the individual bits of the I/O port is a simple
|
|
way of controlling solid state relays, optocouplers, LED's and so on. You
|
|
could very easily and very safely control a high wattage lighting system in
|
|
this manner. (assuming you are using solid state relays with back EMF
|
|
protection). This could/would be good for closet cultivators experimenting
|
|
with the horticulture of cannabis sativa or any other plant. Have you ever
|
|
wanted things such as lights and irrigation systems to come on or turn off at
|
|
certain times? That's what your crontab file is for! The possibilities are
|
|
endless.
|
|
|
|
|
|
I N P U T
|
|
|
|
Standard IBM/PC parallel printer ports have nine control lines capable of
|
|
inputting real world data. Each printer port has three address locations. The
|
|
base address is used to transmit data. The next address can input five data
|
|
bits, using pins 11, 10, 12, 13, and 15 (referred to as BASE_ADDRESS+1 I7
|
|
through I3), and the third port address can input or output a nibble of
|
|
information using pins 17, 16, 14, and 1 (referred to as BASE_ADDRESS+2 I3
|
|
through I0). The third port address pins must be set HIGH so we can read from
|
|
BASE_ADDRESS+2. I'll show you how in the example.
|
|
|
|
The inputs are all active LOW, meaning your device must short them to ground
|
|
to create a signal (switch, analog to digital converter, DTMF decoder, etc).
|
|
This is not a problem, as most devices already do this. The ones that don't,
|
|
just use an inverter.
|
|
|
|
The simplest method of inputting eight data bits is to read the high nibble
|
|
from the (BASE_ADDRESS+1) and the low nibble from the (BASE_ADDRESS+2). These
|
|
two nibbles can be logically ORed together to form a data byte. Some of the
|
|
data bits are hard-wired on the printer card for active HIGH operation. To
|
|
get around this, I use four sections of a 7404 hex inverter to re-invert the
|
|
inverted data lines.
|
|
|
|
I7 I6 I5 I4 I3 I2 I1 I0 BASE_ADDRESS+1 INPUT LINES
|
|
11 10 12 13 15 -- -- -- PIN NUMBER (-- = NOT USED)
|
|
|
|
I7 I6 I5 I4 I3 I2 I1 I0 BASE_ADDRESS+2 INPUT LINES
|
|
-- -- -- -- 17 16 14 1 PIN NUMBER (-- = NOT USED)
|
|
|
|
Notice both I3's of both ports are used. Pin 15 (ERROR) is the 9th input
|
|
of a standard IBM/PC parallel printer port. No offense to this pin, but it's
|
|
a pain in the ass to use and I only use it when I *have* to. Through
|
|
software, I disregard it.
|
|
|
|
Check out this example:
|
|
|
|
/* next line sets all open collector output pins HIGH
|
|
so we can read from BASE_ADDRESS+2) */
|
|
outb(inb(BASE_ADDRESS+2) || 15 , BASE_ADDRESS+2);
|
|
High_Nibble = inb(BASE_ADDRESS+1);
|
|
Low_Nibble = inb(BASE_ADDRESS+2);
|
|
High_Nibble = High_Nibble & 0xF0; /* 0xF0 = 11110000 */
|
|
Low_Nibble = Low_Nibble & 0x0F; /* 0x0F = 00001111 */
|
|
Data_Byte = High_Nibble | Low_Nibble;
|
|
|
|
Pretty simple, eh? This means you can use I7 through I4 in BASE_ADDRESS+1
|
|
and I3 through I0 in BASE_ADDRESS+2 to give you 8 bits of data input.
|
|
|
|
All of the data lines must use a pull up resistor. This includes the
|
|
hard-wired active HIGH pins *after* the 7404 inverter. This lets any device
|
|
produce both a high and low logic signal. Pull up resistors simply pull all
|
|
the data lines high so software sees all 0's unless you short a pin to ground.
|
|
(Remember these are all active LOW inputs -ground means 1)
|
|
|
|
Pins 14, 17, 1, and 11 are all hard-wired for active HIGH operation. These
|
|
are the pins that are signaled through the 7404 inverter IC (which makes them
|
|
just like the rest of the pins for ease of use).
|
|
|
|
NOTES:
|
|
|
|
*** When compiling programs using these routines, use the -O2 optimize flag,
|
|
or else you'll have some headaches.
|
|
|
|
Port 888 is the 1st parallel printer port (LPT1)
|
|
|
|
I am not responsible for your mistakes. If you plug 120vAC directly into
|
|
your parallel port, I guarantee you'll destroy your computer. Use optically
|
|
isolated solid state relays to switch high current.
|
|
|
|
For any more info regarding I/O port programming, schematics to some fun
|
|
projects, or to send a complaint, e-mail professr@hackerz.org
|
|
|
|
If you don't like my code, keep in mind that I design hardware for a living.
|
|
I am not a programmer, nor have I ever claimed to be one. My programs are
|
|
elegant on occasion, but mostly just get the job done without actually doing
|
|
it the best way.
|
|
|
|
If you want schematics showing how to hook up the 7404 to the port, mail me.
|
|
|
|
I have some interesting things there regarding circuit design. One of my
|
|
favorites is a software package called "PADS" Personal Automated Design
|
|
Software. It is a CAD package for schematics and PCBoard Design. The copy
|
|
on my web page is a public domain demo. This demo is fully functional in
|
|
every way. It only limits you to something like 20 IC's, 300 tie points, etc.
|
|
I usually do not go over these limits.
|
|
|
|
Maybe this article will replace the IO-Port [mini] How-To 'cause that is only
|
|
about 24 lines of text.
|
|
|
|
E X A M P L E S
|
|
A N D
|
|
D I A G R A M
|
|
|
|
/* simple program to send data via parallel port */
|
|
|
|
#include <unistd.h>
|
|
#include <asm/io.h>
|
|
#define BASE_ADDRESS 888 /* 1st Parallel Port */
|
|
|
|
main() {
|
|
int port_data=0;
|
|
int Data_Byte=255;
|
|
ioperm(BASE_ADDRESS,3,1); /* set permission on port */
|
|
outb(Data_Byte,BASE_ADDRESS);
|
|
printf("Sent 255 to port %d to turn all pins HIGH\n",BASE_ADDRESS);
|
|
ioperm(BASE_ADDRESS,3,0); /* take away port permission */
|
|
return(0);
|
|
}
|
|
/* end of simple program to send data via parallel port */
|
|
/****************************************************************************/
|
|
/* simple program to take in 8 bit input via parallel port */
|
|
|
|
#include <unistd.h>
|
|
#include <asm/io.h>
|
|
#define BASE_ADDRESS 888 /* 1st Parallel Port */
|
|
|
|
main() {
|
|
int port_data=0;
|
|
int High_Nibble, Low_Nibble, Data_Byte;
|
|
ioperm(BASE_ADDRESS,3,1); /* set permission on port */
|
|
outb(inb(BASE_ADDRESS+2) || 15 , BASE_ADDRESS+2);
|
|
High_Nibble = inb(BASE_ADDRESS+1);
|
|
Low_Nibble = inb(BASE_ADDRESS+2);
|
|
High_Nibble = High_Nibble & 0xF0; /* 0xF0 = 11110000 */
|
|
Low_Nibble = Low_Nibble & 0x0F; /* 0x0F = 00001111 */
|
|
Data_Byte = High_Nibble | Low_Nibble;
|
|
printf("LN=%d HN=%d DB=%d\n",Low_Nibble,High_Nibble,Data_Byte);
|
|
ioperm(BASE_ADDRESS,3,0); /* take away port permission */
|
|
return(0);
|
|
}
|
|
/* end of simple program to take in 8 bit input via parallel port */
|
|
/****************************************************************************/
|
|
I I I I I
|
|
0 6 7 5 4
|
|
|
|
P
|
|
A
|
|
_ P
|
|
S E S
|
|
T R E
|
|
R _ B | L
|
|
O A U E E
|
|
B D D D D D D D D C S N C
|
|
E 0 1 2 3 4 5 6 7 K Y D T
|
|
_____________________________________
|
|
1 (o o o o o o o o o o o o o) 13
|
|
14 \ o o o o o o o o o o o o/ 25
|
|
`---------------------------------'
|
|
_ _ | PINS 18 |
|
|
A E I S |<----THROUGH 25---->|
|
|
U R N E | GROUND |
|
|
T R I L
|
|
O O T |
|
|
| R I
|
|
F N
|
|
E P
|
|
E U
|
|
D * T ** ERROR LINE IS NOT USED AS I3
|
|
* (DISREGARDED VIA SOFTWARE)
|
|
I I I I
|
|
1 3 2 3
|
|
|
|
/******************** End of my little text file / how-to *******************/
|
|
|
|
EOF
|