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.
248 lines
7.2 KiB
248 lines
7.2 KiB
/***************************************************************************
|
|
* Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> *
|
|
* Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> *
|
|
* Copyright (C) 2002-2003 Stephen Landamore <stephen@landamore.com> *
|
|
* *
|
|
* 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 "parallel.h"
|
|
|
|
#include "common/global/global.h"
|
|
#if defined(HAVE_PPDEV)
|
|
# include <linux/ppdev.h>
|
|
# include <linux/parport.h>
|
|
# include <fcntl.h>
|
|
# include <sys/ioctl.h>
|
|
# include <unistd.h> // needed on some system
|
|
# include <errno.h>
|
|
#elif defined(HAVE_PPBUS)
|
|
# include <sys/param.h>
|
|
# include <machine/cpufunc.h>
|
|
# include <dev/ppbus/ppi.h>
|
|
# include <dev/ppbus/ppbconf.h>
|
|
# include <fcntl.h>
|
|
# include <unistd.h>
|
|
# include <errno.h>
|
|
#endif
|
|
#include "common/common/misc.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
TQStringList *Port::Parallel::_list = 0;
|
|
|
|
Port::IODirs Port::Parallel::probe(const TQString &device)
|
|
{
|
|
#if defined(HAVE_PPDEV)
|
|
int fd = ::open(device.latin1(), O_RDWR);
|
|
if ( fd<0) return NoIO;
|
|
if ( ioctl(fd, PPCLAIM)<0 ) {
|
|
::close(fd) ;
|
|
return In;
|
|
}
|
|
ioctl(fd, PPRELEASE);
|
|
::close(fd);
|
|
return (In | Out);
|
|
#elif defined(HAVE_PPBUS)
|
|
int fd = ::open(device.latin1(), O_RDWR);
|
|
if ( fd<0 ) return NoIO;
|
|
::close(fd);
|
|
return In | Out; // #### can we detect read-only ?
|
|
#else
|
|
return NoIO;
|
|
#endif
|
|
}
|
|
|
|
TQStringList Port::Parallel::deviceList()
|
|
{
|
|
TQStringList list;
|
|
#if defined(HAVE_PPDEV)
|
|
// standard parport in user space
|
|
for(int i = 0; i<8; ++i) list.append(TQString("/dev/parport%1").tqarg(i));
|
|
// new devfs parport flavour
|
|
for(int i = 0; i<8; ++i) list.append(TQString("/dev/parports/%1").tqarg(i));
|
|
#elif defined(HAVE_PPBUS)
|
|
// FreeBSD
|
|
for(int i = 0; i<8; ++i) list.append(TQString("/dev/ppi%1").tqarg(i));
|
|
#endif
|
|
return list;
|
|
}
|
|
|
|
const TQStringList &Port::Parallel::probedDeviceList()
|
|
{
|
|
if ( _list==0 ) {
|
|
TQStringList all = deviceList();
|
|
_list = new TQStringList;
|
|
for (uint i=0; i<uint(all.count()); i++)
|
|
if( probe(all[i]) & (In | Out) ) _list->append(all[i]);
|
|
}
|
|
return *_list;
|
|
}
|
|
|
|
bool Port::Parallel::isAvailable()
|
|
{
|
|
#if defined(HAVE_PPDEV) || defined(HAVE_PPBUS)
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
const Port::Parallel::PPinData Port::Parallel::PIN_DATA[Nb_Pins] = {
|
|
{ Control, 0x01, Out, "/DS" }, // !strobe
|
|
{ Data, 0x01, Out, "D0" }, // data 0
|
|
{ Data, 0x02, Out, "D1" }, // data 1
|
|
{ Data, 0x04, Out, "D2" }, // data 2
|
|
{ Data, 0x08, Out, "D3" }, // data 3
|
|
{ Data, 0x10, Out, "D4" }, // data 4
|
|
{ Data, 0x20, Out, "D5" }, // data 5
|
|
{ Data, 0x40, Out, "D6" }, // data 6
|
|
{ Data, 0x80, Out, "D7" }, // data 7
|
|
{ tqStatus, 0x40, In, "/ACK" }, // !ack
|
|
{ tqStatus, 0x80, In, "BUSY" }, // busy
|
|
{ tqStatus, 0x20, In, "PAPER" }, // pout
|
|
{ tqStatus, 0x10, In, "SELin" }, // select
|
|
{ Control, 0x02, Out, "LF" }, // !feed
|
|
{ tqStatus, 0x08, In, "/ERROR" }, // !error
|
|
{ Control, 0x04, Out, "PRIME" }, // !init
|
|
{ Control, 0x08, Out, "SELout" }, // !si
|
|
{ Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND
|
|
{ Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND
|
|
{ Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND
|
|
{ Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND
|
|
{ Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND
|
|
{ Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND
|
|
{ Nb_RequestTypes, 0x00, NoIO, "GND" }, // GND
|
|
{ Nb_RequestTypes, 0x00, NoIO, "GND" } // GND
|
|
};
|
|
|
|
TQValueVector<Port::PinData> Port::Parallel::pinData(IODir dir) const
|
|
{
|
|
TQValueVector<PinData> v;
|
|
for (uint i=0; i<Nb_Pins; i++) {
|
|
if ( PIN_DATA[i].dir!=dir ) continue;
|
|
PinData pd = { i, PIN_DATA[i].label };
|
|
v.append(pd);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
bool Port::Parallel::isGroundPin(uint pin) const
|
|
{
|
|
return ( PIN_DATA[pin].label==TQString("GND") );
|
|
}
|
|
|
|
Port::IODir Port::Parallel::ioDir(uint pin) const
|
|
{
|
|
return PIN_DATA[pin].dir;
|
|
}
|
|
|
|
const Port::Parallel::RequestData Port::Parallel::REQUEST_DATA[Nb_RequestTypes] = {
|
|
#if defined(HAVE_PPDEV)
|
|
{ PPRCONTROL, PPWCONTROL },
|
|
{ PPRSTATUS, 0 },
|
|
{ PPRDATA, PPWDATA }
|
|
#elif defined(HAVE_PPBUS)
|
|
{ PPIGCTRL, PPISCTRL },
|
|
{ PPIGSTATUS, 0 },
|
|
{ PPIGDATA, PPISDATA }
|
|
#else
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 }
|
|
#endif
|
|
};
|
|
|
|
Port::Parallel::Parallel(const TQString &device, Log::Base &base)
|
|
: Base(base), _fd(-1), _device(device)
|
|
{
|
|
for (uint i=0; i<Nb_RequestTypes; i++) _images[i] = 0;
|
|
}
|
|
|
|
bool Port::Parallel::internalOpen()
|
|
{
|
|
#if defined(HAVE_PPDEV)
|
|
_fd = ::open(_device.latin1(), O_RDWR);
|
|
if ( _fd<0 ) {
|
|
setSystemError(i18n("Could not open device \"%1\"").tqarg(_device));
|
|
return false;
|
|
}
|
|
if ( ioctl(_fd, PPCLAIM)<0 ) {
|
|
setSystemError(i18n("Could not claim device \"%1\": check it is read/write enabled").tqarg(_device));
|
|
return false;
|
|
}
|
|
#elif defined(HAVE_PPBUS)
|
|
_fd = ::open(_device.latin1(), O_RDWR);
|
|
if ( _fd<0 ) {
|
|
setSystemError(i18n("Could not open device \"%1\"").tqarg(_device));
|
|
return false;
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
void Port::Parallel::internalClose()
|
|
{
|
|
if ( _fd<0 ) return;
|
|
#if defined(HAVE_PPDEV)
|
|
ioctl(_fd, PPRELEASE);
|
|
::close(_fd);
|
|
#elif defined(HAVE_PPBUS)
|
|
::close(_fd);
|
|
#endif
|
|
_fd = -1;
|
|
}
|
|
|
|
bool Port::Parallel::setPinOn(uint pin, bool on, LogicType type)
|
|
{
|
|
if ( _fd<0 ) return false;
|
|
#if defined(HAVE_PPDEV) || defined(HAVE_PPBUS)
|
|
Q_ASSERT( pin<Nb_Pins );
|
|
Q_ASSERT( PIN_DATA[pin].dir==Out );
|
|
RequestType rtype = PIN_DATA[pin].rType;
|
|
Q_ASSERT( rtype!=Nb_RequestTypes );
|
|
uchar mask = PIN_DATA[pin].mask;
|
|
uchar c = (XOR(type==NegativeLogic, on) ? _images[rtype] | mask : _images[rtype] & ~mask);
|
|
int request = REQUEST_DATA[rtype].write;
|
|
Q_ASSERT( request!=0 );
|
|
if ( ioctl(_fd, request, &c)<0 ) {
|
|
setSystemError(i18n("Error setting pin %1 to %2").tqarg(PIN_DATA[pin].label).tqarg(on));
|
|
return false;
|
|
}
|
|
_images[rtype] = c;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
bool Port::Parallel::readPin(uint pin, LogicType type, bool &value)
|
|
{
|
|
if ( _fd<0 ) return false;
|
|
#if defined(HAVE_PPDEV) || defined(HAVE_PPBUS)
|
|
Q_ASSERT( pin<Nb_Pins );
|
|
Q_ASSERT( PIN_DATA[pin].dir==In );
|
|
RequestType rtype = PIN_DATA[pin].rType;
|
|
Q_ASSERT( rtype!=Nb_RequestTypes );
|
|
int request = REQUEST_DATA[rtype].read;
|
|
Q_ASSERT( request!=0 );
|
|
uchar c = 0;
|
|
if ( ioctl(_fd, request, &c)<0 ) {
|
|
setSystemError(i18n("Error reading bit on pin %1").tqarg(PIN_DATA[pin].label));
|
|
return false;
|
|
}
|
|
_images[rtype] = c;
|
|
value = (type==NegativeLogic ? ~c : c ) & PIN_DATA[pin].mask;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
void Port::Parallel::setSystemError(const TQString &message)
|
|
{
|
|
#if defined(HAVE_PPDEV) || defined(HAVE_PPBUS)
|
|
log(Log::LineType::Error, message + TQString(" (errno=%1).").tqarg(strerror(errno)));
|
|
#else
|
|
Q_UNUSED(message);
|
|
#endif
|
|
}
|