You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
515 lines
9.1 KiB
515 lines
9.1 KiB
/***************************************************************************
|
|
* Copyright (C) 2005 by David Saxton *
|
|
* david@bluehaze.org *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
***************************************************************************/
|
|
|
|
#include "port.h"
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <linux/ppdev.h>
|
|
#include <sys/ioctl.h>
|
|
#include <unistd.h>
|
|
|
|
//BEGIN class Port
|
|
Port::Port()
|
|
{
|
|
}
|
|
|
|
|
|
Port::~Port()
|
|
{
|
|
}
|
|
|
|
|
|
TQStringList Port::ports( unsigned probeResult )
|
|
{
|
|
return SerialPort::ports(probeResult) + ParallelPort::ports(probeResult);
|
|
}
|
|
//END class Port
|
|
|
|
|
|
|
|
//BEGIN class SerialPort
|
|
SerialPort::SerialPort()
|
|
{
|
|
m_file = -1;
|
|
}
|
|
|
|
|
|
SerialPort::~SerialPort()
|
|
{
|
|
closePort();
|
|
}
|
|
|
|
|
|
void SerialPort::setPinState( Pin pin, bool state )
|
|
{
|
|
if ( m_file == -1 )
|
|
return;
|
|
|
|
int flags = -1;
|
|
|
|
switch ( pin )
|
|
{
|
|
case TD:
|
|
ioctl( m_file, state ? TIOCSBRK : TIOCCBRK, 0 );
|
|
return;
|
|
|
|
case DTR:
|
|
flags = TIOCM_DTR;
|
|
break;
|
|
|
|
case DSR:
|
|
flags = TIOCM_DSR;
|
|
break;
|
|
|
|
case RTS:
|
|
flags = TIOCM_RTS;
|
|
break;
|
|
|
|
case CD:
|
|
case RD:
|
|
case GND:
|
|
case CTS:
|
|
case RI:
|
|
break;
|
|
};
|
|
|
|
if ( flags == -1 )
|
|
{
|
|
kdError() << k_funcinfo << "Bad pin " << pin << endl;
|
|
return;
|
|
}
|
|
|
|
if ( ioctl( m_file, state ? TIOCMBIS : TIOCMBIC, & flags ) == -1 )
|
|
kdError() << k_funcinfo << "Could not set pin " << pin << " errno = " << errno << endl;
|
|
}
|
|
|
|
|
|
bool SerialPort::pinState( Pin pin )
|
|
{
|
|
if ( m_file == -1 )
|
|
return false;
|
|
|
|
int mask = 0;
|
|
|
|
switch ( pin )
|
|
{
|
|
case CD:
|
|
mask = TIOCM_CD;
|
|
break;
|
|
|
|
case RD:
|
|
mask = TIOCM_SR;
|
|
break;
|
|
|
|
case CTS:
|
|
mask = TIOCM_CTS;
|
|
break;
|
|
|
|
case RI:
|
|
mask = TIOCM_RI;
|
|
break;
|
|
|
|
case TD:
|
|
case DTR:
|
|
case GND:
|
|
case DSR:
|
|
case RTS:
|
|
break;
|
|
}
|
|
|
|
if ( mask == 0 )
|
|
{
|
|
kdError() << k_funcinfo << "Bad pin " << pin << endl;
|
|
return false;
|
|
}
|
|
|
|
int bits = 0;
|
|
if ( ioctl( m_file, TIOCMGET, & bits ) == -1 )
|
|
{
|
|
kdError() << k_funcinfo << "Could not read pin" << pin << " errno = " << errno << endl;
|
|
return false;
|
|
}
|
|
|
|
return bits & mask;
|
|
}
|
|
|
|
|
|
Port::ProbeResult SerialPort::probe( const TQString & port )
|
|
{
|
|
int file = open( port.ascii(), O_NOCTTY | O_NONBLOCK | O_RDONLY );
|
|
if ( file == -1 )
|
|
return Port::DoesntExist;
|
|
|
|
close(file);
|
|
|
|
file = open( port.ascii(), O_NOCTTY | O_NONBLOCK | O_RDWR );
|
|
if ( file == -1 )
|
|
return Port::ExistsButNotRW;
|
|
close(file);
|
|
|
|
return Port::ExistsAndRW;
|
|
}
|
|
|
|
|
|
bool SerialPort::openPort( const TQString & port, speed_t baudRate )
|
|
{
|
|
closePort();
|
|
|
|
m_file = open( port.ascii(), O_NOCTTY | O_NONBLOCK | O_RDWR );
|
|
if ( m_file == -1 )
|
|
{
|
|
kdError() << k_funcinfo << "Could not open port " << port << endl;
|
|
return false;
|
|
}
|
|
|
|
termios state;
|
|
tcgetattr( m_file, & state );
|
|
|
|
// Save the previous state for restoration in close.
|
|
m_previousState = state;
|
|
|
|
state.c_iflag = IGNBRK | IGNPAR;
|
|
state.c_oflag = 0;
|
|
state.c_cflag = baudRate | CS8 | CREAD | CLOCAL;
|
|
state.c_lflag = 0;
|
|
tcsetattr( m_file, TCSANOW, & state );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void SerialPort::closePort()
|
|
{
|
|
if ( m_file == -1 )
|
|
return;
|
|
|
|
ioctl( m_file, TIOCCBRK, 0 );
|
|
usleep(1);
|
|
tcsetattr( m_file, TCSANOW, & m_previousState );
|
|
close( m_file );
|
|
m_file = -1;
|
|
}
|
|
|
|
|
|
TQStringList SerialPort::ports( unsigned probeResult )
|
|
{
|
|
TQStringList list;
|
|
|
|
for ( int i = 0; i < 8; ++i )
|
|
{
|
|
TQString dev = TQString("/dev/ttyS%1").arg(i);
|
|
if ( probe(dev) & probeResult )
|
|
list << dev;
|
|
}
|
|
|
|
for ( unsigned i = 0; i < 8; ++i )
|
|
{
|
|
TQString dev = TQString("/dev/tts/%1").arg(i);
|
|
if ( probe(dev) & probeResult )
|
|
list << dev;
|
|
}
|
|
|
|
for ( unsigned i = 0; i < 8; ++i )
|
|
{
|
|
TQString dev = TQString("/dev/ttyUSB%1").arg(i);
|
|
if ( probe(dev) & probeResult )
|
|
list << dev;
|
|
}
|
|
|
|
for ( unsigned i = 0; i < 8; ++i )
|
|
{
|
|
TQString dev = TQString("/dev/usb/tts/%1").arg(i);
|
|
if ( probe(dev) & probeResult )
|
|
list << dev;
|
|
}
|
|
|
|
return list;
|
|
}
|
|
//END class SerialPort
|
|
|
|
|
|
|
|
//BEGIN class ParallelPort
|
|
const int IRQ_MODE_BIT = 1 << 20; // Controls if pin 10 (Ack) causes interrupts
|
|
const int INPUT_MODE_BIT = 1 << 21; // Controls if the data pins are input or output
|
|
const int ALWAYS_INPUT_PINS = ParallelPort::STATUS_PINS;
|
|
|
|
const unsigned int IOCTL_REG_READ[3] = {
|
|
PPRDATA,
|
|
PPRSTATUS,
|
|
PPRCONTROL,
|
|
};
|
|
|
|
const unsigned int IOCTL_REG_WRITE[3] = {
|
|
PPWDATA,
|
|
0,
|
|
PPWCONTROL,
|
|
};
|
|
|
|
const int INVERT_MASK[3] = {
|
|
0x0,
|
|
0x80, // 10000000
|
|
0x0b, // 00001011
|
|
};
|
|
|
|
ParallelPort::ParallelPort()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
|
|
ParallelPort::~ParallelPort()
|
|
{
|
|
}
|
|
|
|
|
|
void ParallelPort::reset()
|
|
{
|
|
m_file = -1;
|
|
m_reg[Data] = 0;
|
|
m_reg[Status] = 0;
|
|
m_reg[Control] = 0;
|
|
m_outputPins = INPUT_MODE_BIT | IRQ_MODE_BIT;
|
|
m_inputPins = ALWAYS_INPUT_PINS | INPUT_MODE_BIT | IRQ_MODE_BIT;
|
|
}
|
|
|
|
|
|
//BEGIN Pin-oriented operations
|
|
void ParallelPort::setPinState( int pins, bool state )
|
|
{
|
|
// only allow writing to output pins
|
|
pins &= m_outputPins;
|
|
|
|
if ( pins & DATA_PINS )
|
|
setDataState( (pins & DATA_PINS) >> 0, state );
|
|
|
|
if ( pins & CONTROL_PINS )
|
|
setControlState( (pins & CONTROL_PINS) >> 16, state );
|
|
}
|
|
|
|
|
|
int ParallelPort::pinState( int pins )
|
|
{
|
|
int value = 0;
|
|
|
|
// only allow reading from input pins
|
|
pins &= m_inputPins;
|
|
|
|
if ( pins & DATA_PINS )
|
|
value |= ((readFromRegister( Data ) & ((pins & DATA_PINS) >> 0)) << 0);
|
|
|
|
if ( pins & STATUS_PINS )
|
|
value |= ((readFromRegister( Status ) & ((pins & STATUS_PINS) >> 8)) << 8);
|
|
|
|
if ( pins & CONTROL_PINS )
|
|
value |= ((readFromRegister( Control ) & ((pins & CONTROL_PINS) >> 16)) << 16);
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
void ParallelPort::setDataState( uchar pins, bool state )
|
|
{
|
|
uchar value = readFromRegister( Data );
|
|
|
|
if ( state )
|
|
value |= pins;
|
|
else
|
|
value &= ~pins;
|
|
|
|
writeToData( value );
|
|
}
|
|
|
|
|
|
void ParallelPort::setControlState( uchar pins, bool state )
|
|
{
|
|
uchar value = readFromRegister( Control );
|
|
|
|
if ( state )
|
|
value |= pins;
|
|
else
|
|
value &= ~pins;
|
|
|
|
writeToControl( value );
|
|
}
|
|
//END Pin-oriented operations
|
|
|
|
|
|
|
|
//BEGIN Register-oriented operations
|
|
uchar ParallelPort::readFromRegister( Register reg )
|
|
{
|
|
if ( m_file == -1 )
|
|
return 0;
|
|
|
|
// uchar value = inb( m_lpBase + reg ) ^ INVERT_MASK[reg];
|
|
uchar value = 0;
|
|
if ( ioctl( m_file, IOCTL_REG_READ[reg], &value ) )
|
|
kdError() << k_funcinfo << "errno=" << errno << endl;
|
|
else
|
|
m_reg[reg] = value;
|
|
return value;
|
|
}
|
|
|
|
|
|
void ParallelPort::writeToRegister( Register reg, uchar value )
|
|
{
|
|
if ( m_file == -1 )
|
|
return;
|
|
|
|
// outb( value ^ INVERT_MASK[reg], m_lpBase + reg );
|
|
if ( ioctl( m_file, IOCTL_REG_WRITE[reg], & value ) )
|
|
kdError() << k_funcinfo << "errno=" << errno << endl;
|
|
else
|
|
m_reg[reg] = value;
|
|
}
|
|
|
|
|
|
void ParallelPort::writeToData( uchar value )
|
|
{
|
|
writeToRegister( Data, value );
|
|
}
|
|
|
|
|
|
void ParallelPort::writeToControl( uchar value )
|
|
{
|
|
// Set all inputs to ones
|
|
value |= ((m_inputPins & CONTROL_PINS) >> 16);
|
|
|
|
writeToRegister( Control, value );
|
|
}
|
|
//END Register-oriented operations
|
|
|
|
|
|
//BEGIN Changing pin directions
|
|
void ParallelPort::setDataDirection( Direction dir )
|
|
{
|
|
if ( dir == Input )
|
|
{
|
|
m_inputPins |= DATA_PINS;
|
|
m_outputPins &= ~DATA_PINS;
|
|
}
|
|
else
|
|
{
|
|
m_inputPins &= DATA_PINS;
|
|
m_outputPins |= ~DATA_PINS;
|
|
}
|
|
|
|
setPinState( INPUT_MODE_BIT, dir == Input );
|
|
}
|
|
|
|
|
|
void ParallelPort::setControlDirection( int pins, Direction dir )
|
|
{
|
|
pins &= CONTROL_PINS;
|
|
|
|
if ( dir == Input )
|
|
{
|
|
m_inputPins |= pins;
|
|
m_outputPins &= ~pins;
|
|
}
|
|
else
|
|
{
|
|
m_inputPins &= pins;
|
|
m_outputPins |= ~pins;
|
|
}
|
|
|
|
setControlState( 0, true );
|
|
}
|
|
//END Changing pin directions
|
|
|
|
|
|
Port::ProbeResult ParallelPort::probe( const TQString & port )
|
|
{
|
|
int file = open( port.ascii(), O_RDWR );
|
|
if ( file == -1 )
|
|
return Port::DoesntExist;
|
|
|
|
if ( ioctl( file, PPCLAIM ) != 0 )
|
|
{
|
|
close(file);
|
|
return Port::ExistsButNotRW;
|
|
}
|
|
|
|
ioctl( file, PPRELEASE );
|
|
close(file);
|
|
return Port::ExistsAndRW;
|
|
}
|
|
|
|
|
|
TQStringList ParallelPort::ports( unsigned probeResult )
|
|
{
|
|
TQStringList list;
|
|
|
|
for ( unsigned i = 0; i < 8; ++i )
|
|
{
|
|
TQString dev = TQString("/dev/parport%1").arg(i);
|
|
if ( probe(dev) & probeResult )
|
|
list << dev;
|
|
}
|
|
|
|
for ( unsigned i = 0; i < 8; ++i )
|
|
{
|
|
TQString dev = TQString("/dev/parports/%1").arg(i);
|
|
if ( probe(dev) & probeResult )
|
|
list << dev;
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
|
|
bool ParallelPort::openPort( const TQString & port )
|
|
{
|
|
if ( m_file != -1 )
|
|
{
|
|
kdWarning() << k_funcinfo << "Port already open" << endl;
|
|
return false;
|
|
}
|
|
|
|
m_file = open( port.ascii(), O_RDWR );
|
|
|
|
if ( m_file == -1 )
|
|
{
|
|
kdError() << k_funcinfo << "Could not open port \"" << port << "\": errno="<<errno<<endl;
|
|
return false;
|
|
}
|
|
|
|
if ( ioctl( m_file, PPCLAIM ) )
|
|
{
|
|
kdError() << k_funcinfo << "Port " << port << " must be RW" << endl;
|
|
close( m_file );
|
|
m_file = -1;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void ParallelPort::closePort()
|
|
{
|
|
if ( m_file == -1 )
|
|
return;
|
|
|
|
int res = ioctl( m_file, PPRELEASE );
|
|
close( m_file );
|
|
|
|
if ( res )
|
|
kdError() << k_funcinfo << "res="<<res<<endl;
|
|
|
|
m_file = -1;
|
|
}
|
|
//END class ParallelPort
|
|
|