summaryrefslogtreecommitdiffstats
path: root/src/common/port/parallel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/port/parallel.cpp')
-rw-r--r--src/common/port/parallel.cpp247
1 files changed, 247 insertions, 0 deletions
diff --git a/src/common/port/parallel.cpp b/src/common/port/parallel.cpp
new file mode 100644
index 0000000..22b6a4c
--- /dev/null
+++ b/src/common/port/parallel.cpp
@@ -0,0 +1,247 @@
+/***************************************************************************
+ * 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"
+
+//-----------------------------------------------------------------------------
+QStringList *Port::Parallel::_list = 0;
+
+Port::IODirs Port::Parallel::probe(const QString &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
+}
+
+QStringList Port::Parallel::deviceList()
+{
+ QStringList list;
+#if defined(HAVE_PPDEV)
+ // standard parport in user space
+ for(int i = 0; i<8; ++i) list.append(QString("/dev/parport%1").arg(i));
+ // new devfs parport flavour
+ for(int i = 0; i<8; ++i) list.append(QString("/dev/parports/%1").arg(i));
+#elif defined(HAVE_PPBUS)
+ // FreeBSD
+ for(int i = 0; i<8; ++i) list.append(QString("/dev/ppi%1").arg(i));
+#endif
+ return list;
+}
+
+const QStringList &Port::Parallel::probedDeviceList()
+{
+ if ( _list==0 ) {
+ QStringList all = deviceList();
+ _list = new QStringList;
+ 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
+ { Status, 0x40, In, "/ACK" }, // !ack
+ { Status, 0x80, In, "BUSY" }, // busy
+ { Status, 0x20, In, "PAPER" }, // pout
+ { Status, 0x10, In, "SELin" }, // select
+ { Control, 0x02, Out, "LF" }, // !feed
+ { Status, 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
+};
+
+QValueVector<Port::PinData> Port::Parallel::pinData(IODir dir) const
+{
+ QValueVector<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==QString("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 QString &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\"").arg(_device));
+ return false;
+ }
+ if ( ioctl(_fd, PPCLAIM)<0 ) {
+ setSystemError(i18n("Could not claim device \"%1\": check it is read/write enabled").arg(_device));
+ return false;
+ }
+#elif defined(HAVE_PPBUS)
+ _fd = ::open(_device.latin1(), O_RDWR);
+ if ( _fd<0 ) {
+ setSystemError(i18n("Could not open device \"%1\"").arg(_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").arg(PIN_DATA[pin].label).arg(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").arg(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 QString &message)
+{
+#if defined(HAVE_PPDEV) || defined(HAVE_PPBUS)
+ log(Log::LineType::Error, message + QString(" (errno=%1).").arg(strerror(errno)));
+#else
+ Q_UNUSED(message);
+#endif
+}