_DIGITAL I/O WITH THE PC_ by Brian Hook and Dennis Shuman Listing One //----------------------------------------------------------------- // PPDIO Parallel Port Digital IO routines // Version 1.0 Copyright 1993 by Brian Hook. All Rights Reserved. // File: PPDIO.H -- header file for the PPDIO library // Compile with Borland C++ 3.1 -- porting to another compiler // should be extremely trivial. //----------------------------------------------------------------- #ifndef __PPDIO_H #define __PPDIO_H //--- Pin definitions for control register ------------------------ #define PIN_1 0x01 #define PIN_14 0x02 #define PIN_16 0x04 #define PIN_17 0x08 //--- Pin definitions for status register ------------------------- #define PIN_15 0x08 #define PIN_13 0x10 #define PIN_12 0x20 #define PIN_10 0x40 #define PIN_11 0x80 //--- Interrupt enable bit definition ----------------------------- #define PTR_ENABLE_INT_BIT 0x10 //--- Function prototypes ----------------------------------------- unsigned PPDIO_GetLptAddress( int lpt_port ); void PPDIO_InstallISR( void interrupt (*fnc)(), int irq ); unsigned char PPDIO_ReadControlRaw( void ); unsigned char PPDIO_ReadStatusRaw( void ); unsigned char PPDIO_ReadControlCooked( void ); unsigned char PPDIO_ReadStatusRaw( void ); void PPDIO_RemoveISR( void ); void PPDIO_SendByte( unsigned char data ); void PPDIO_SetBaseAddress( unsigned base_address ); void PPDIO_SetLptPort( int lpt_port ); #endif Listing Two //----------------------------------------------------------------- // PPDIO Parallel Port Digital IO routines // Version 1.0 Copyright 1993 by Brian Hook. All Rights Reserved. // File: PPDIO.C -- code and variables for the PPDIO library // Compile with Borland C++ 3.1 -- porting to another compiler // should be extremely trivial. //----------------------------------------------------------------- #include #include "ppdio.h" static unsigned ppdio_data_register; static unsigned ppdio_control_register; static unsigned ppdio_status_register; static unsigned ppdio_interrupt_no; static unsigned ppdio_irq; static unsigned char ppdio_old_control_value; static unsigned char ppdio_old_8259_mask; static void interrupt (*ppdio_old_intvec)(); unsigned PPDIO_GetLptAddress( int lpt_no ) { unsigned far *pp = ( unsigned far * ) MK_FP( 0x40, 8 ); //--- Assumes values of 1, 2, or 3 ----------------------------- return ( pp[lpt_no-1] ); } void PPDIO_InstallISR( void interrupt (*fnc)(), int irq_no ) { static char mask[] = { 0xfa, 0xf7, 0xef, 0xdf, 0xaf, 0x7f }; unsigned char temp; //--- Interrupt number = IRQ no + 8 ---------------------------- ppdio_interrupt_no = irq_no + 8; //--- Save original interrupt vector --------------------------- ppdio_old_intvec = getvect( ppdio_interrupt_no ); //--- Install new ISR ------------------------------------------ setvect( ppdio_interrupt_no, fnc ); //--- Enable interrupts by setting the PTR_ENABLE_INT_BIT in //--- the control register. Also, OR it by 0x04 to send pin //--- 16 high then write out a 0 to pins 1, 14, and 17 so //--- that we can use the control register for input. ppdio_old_control_value = inportb( ppdio_control_register ); temp = ppdio_old_control_value | PTR_ENABLE_INT_BIT | PIN_16; temp &= ~ ( PIN_17 | PIN_14 | PIN_1 ); outportb( ppdio_control_register, temp ); //--- Unmask our IRQ in the interrupt controller --------------- ppdio_old_8259_mask = inportb( 0x21 ); temp = ppdio_old_8259_mask & mask[ppdio_interrupt_no-10]; outportb( 0x21, temp ); //--- Clear pending interrupts --------------------------------- outportb( 0x20, 0x20 ); } unsigned char PPDIO_ReadControlCooked( void ) { unsigned char raw_control; unsigned char cooked_control = 0; raw_control = PPDIO_ReadControlRaw(); //--- Return a control register mask that compensates for the inverse logic //--- of pins 1, 14, and 17, and with 0s where bits are reserved or unused. if ( !( raw_control & PIN_1 ) ) cooked_control |= PIN_1; if ( !( raw_control & PIN_14 ) ) cooked_control |= PIN_14; if ( raw_control & PIN_16 ) cooked_control |= PIN_16; if ( !( raw_control & PIN_17 ) ) cooked_control |= PIN_17; return ( cooked_control ); } unsigned char PPDIO_ReadControlRaw( void ) { return ( inportb( ppdio_control_register ) ); } unsigned char PPDIO_ReadStatusCooked( void ) { unsigned char raw_status; unsigned char cooked_status = 0; raw_status = PPDIO_ReadStatusRaw(); //--- Return a status register mask that compensates for the //--- inverse logic of pin 11, and with 0s for any reserved or unused bits. if ( raw_status & PIN_15 ) cooked_status |= PIN_15; if ( raw_status & PIN_13 ) cooked_status |= PIN_13; if ( raw_status & PIN_12 ) cooked_status |= PIN_12; if ( !( raw_status & PIN_11 ) ) cooked_status |= PIN_11; return ( cooked_status ); } unsigned char PPDIO_ReadStatusRaw( void ) { return ( inportb( ppdio_status_register ) ); } void PPDIO_RemoveISR( void ) { //--- Restore the interrupt controller's previous state -------- outportb( 0x21, ppdio_old_8259_mask ); //--- Restore the original interrupt vector -------------------- setvect( ppdio_interrupt_no, ppdio_old_intvec ); //--- Restore the printer control register --------------------- outportb( ppdio_control_register, ppdio_old_control_value ); } void PPDIO_SendByte( unsigned char data ) { outportb( ppdio_data_register, data ); } void PPDIO_SetBaseAddress( unsigned base_address ) { ppdio_data_register = base_address; ppdio_status_register = base_address + 1; ppdio_control_register = base_address + 2; } void PPDIO_SetLptPort( int lpt_port ) { PPDIO_SetBaseAddress( PPDIO_GetLptAddress( lpt_port ) ); } Listing Three //----------------------------------------------------------------- // PPDIO Parallel Port Digital IO routines // Version 1.0 Copyright 1993 by Brian Hook. All Rights Reserved. // File: DIO.C -- this is an example how you could use the PPDIO // routines. This could be used as a framework upon which you // could build real applications. // Compile with Borland C++ 3.1 -- porting to another compiler // should be extremely trivial. //----------------------------------------------------------------- #include #include "ppdio.h" volatile int isr_called = 0; void huge interrupt MyISR( void ) { isr_called = 1; //--- Normally you would read the input pins here and do something important //--- Signal end of interrupt to the interrupt controller ------ outportb( 0x20, 0x20 ); } void main( void ) { //--- Use LPT1 ------------------------------------------------- PPDIO_SetLptPort( 1 ); //--- Install our ISR on IRQ 5 --------------------------------- PPDIO_InstallISR( MyISR, 5 ); //--- Run until either a key is pressed or interrupt is generated on IRQ 5 while ( !kbhit() && !isr_called ) { } PPDIO_RemoveISR(); }