2008-12-22 18:24:40 +00:00
|
|
|
/** \file server/drivers/serialVFD_io.c
|
|
|
|
|
* Hardware dependent routines for the \c serialVFD driver.
|
|
|
|
|
* Here are the routines for initializing, writing to, and closing the
|
|
|
|
|
* serial resp. parallel port for the \c serialVFD driver.
|
|
|
|
|
*/
|
|
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/*-
|
|
|
|
|
* Copyright (C) 2006 Stefan Herdler
|
|
|
|
|
*
|
|
|
|
|
* This driver is based on wirz-sli.c, hd44780.c, drv_base.c and NoritakeVFD
|
|
|
|
|
* driver. It may contain parts of other drivers of this package too.
|
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
|
|
|
|
*/
|
2006-05-20 14:39:32 +00:00
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/*
|
|
|
|
|
* 2006-05-16 Version 0.3: everything should work (not all hardware tested!)
|
|
|
|
|
*/
|
2006-05-20 14:39:32 +00:00
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
# include "config.h"
|
|
|
|
|
#endif
|
2006-05-20 14:39:32 +00:00
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <termios.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
2006-05-20 14:39:32 +00:00
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
#include "lcd.h"
|
|
|
|
|
#include "report.h"
|
|
|
|
|
#include "lpt-port.h"
|
2006-05-20 14:39:32 +00:00
|
|
|
#include "port.h"
|
|
|
|
|
#include "serialVFD_io.h"
|
|
|
|
|
#include "serialVFD.h"
|
2006-12-08 18:06:59 +00:00
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/*
|
|
|
|
|
* XXX: ENIRQ used to be set, although no IRQ handler is defined. As the
|
|
|
|
|
* schematic in the user guide shows BUSY connected to ACK, leave it as is.
|
|
|
|
|
*/
|
|
|
|
|
#define WR_on ((ENIRQ | STRB) ^ OUTMASK) /* STRB (1) is active low */
|
|
|
|
|
#define WR_off (ENIRQ ^ OUTMASK)
|
2006-05-20 14:39:32 +00:00
|
|
|
|
|
|
|
|
#define MAXBUSY 300
|
|
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/**
|
|
|
|
|
* Write bytes to the serial port.
|
|
|
|
|
* \param drvthis Pointer to driver
|
|
|
|
|
* \param dat Pointer to array storing the data
|
|
|
|
|
* \param length Number of bytes to write
|
|
|
|
|
*/
|
2006-05-20 14:39:32 +00:00
|
|
|
void
|
2006-12-08 18:06:59 +00:00
|
|
|
serialVFD_write_serial (Driver *drvthis, unsigned char *dat, size_t length)
|
2006-05-20 14:39:32 +00:00
|
|
|
{
|
2009-11-01 08:32:50 +00:00
|
|
|
PrivateData *p = drvthis->private_data;
|
|
|
|
|
|
2008-11-23 13:09:11 +00:00
|
|
|
if (length <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2007-04-02 21:29:53 +00:00
|
|
|
write(p->fd,dat,length);
|
2006-05-20 14:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/**
|
|
|
|
|
* Write bytes to the parallel port.
|
|
|
|
|
*
|
|
|
|
|
* Timing can be modified by inserting additional delays according to the
|
|
|
|
|
* \c PortWait setting in \c LCDd.conf: \n
|
|
|
|
|
* Portwait = 0; no delays, only BUSY bit checked\n
|
|
|
|
|
* Portwait = 1; additional WR off to check BUSY delay\n
|
|
|
|
|
* Portwait = 2; as 1 + additional WR pulse width\n
|
|
|
|
|
* Portwait = 3; as 2 + additional WR setup delay\n
|
|
|
|
|
* Portwait >= 4; as 3 + additional wait delay to next command
|
2011-03-28 18:17:58 +00:00
|
|
|
*
|
2010-12-09 21:25:42 +00:00
|
|
|
* \param drvthis Pointer to driver
|
|
|
|
|
* \param dat Pointer to array storing the data
|
|
|
|
|
* \param length Number of bytes to write
|
|
|
|
|
*/
|
2006-05-20 14:39:32 +00:00
|
|
|
void
|
2006-12-08 18:06:59 +00:00
|
|
|
serialVFD_write_parallel (Driver *drvthis, unsigned char *dat, size_t length)
|
2006-05-20 14:39:32 +00:00
|
|
|
{
|
2006-12-08 18:06:59 +00:00
|
|
|
#ifdef HAVE_PCSTYLE_LPT_CONTROL
|
2006-05-20 14:39:32 +00:00
|
|
|
PrivateData *p = drvthis->private_data;
|
|
|
|
|
int i_para, j_para;
|
|
|
|
|
|
2009-11-01 08:32:50 +00:00
|
|
|
if (length <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2007-04-02 21:29:53 +00:00
|
|
|
for (i_para = 0; i_para < length; i_para++) {
|
2006-05-20 14:39:32 +00:00
|
|
|
port_out(p->port, dat[i_para]);
|
2008-05-02 15:48:18 +00:00
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/* data to WR enable delay */
|
|
|
|
|
if (p->para_wait > 2)
|
2008-05-02 15:48:18 +00:00
|
|
|
port_in(p->port+1);
|
|
|
|
|
|
2006-05-20 14:39:32 +00:00
|
|
|
port_out(p->port+2, WR_on);
|
2008-05-02 15:48:18 +00:00
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/* additional WR pulse width */
|
|
|
|
|
if (p->para_wait > 1)
|
2008-05-02 15:48:18 +00:00
|
|
|
port_in(p->port+1);
|
|
|
|
|
|
2006-05-20 14:39:32 +00:00
|
|
|
port_out(p->port+2, WR_off);
|
2008-05-02 15:48:18 +00:00
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/* additional BUSY delay time */
|
|
|
|
|
if (p->para_wait > 0)
|
2008-05-02 15:48:18 +00:00
|
|
|
port_in(p->port+1);
|
|
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/*
|
|
|
|
|
* Check MAXBUSY times if the BUSY bit is set. Note: BUSY bit
|
|
|
|
|
* on parallel port is hardware inverted, but VFD is ready
|
|
|
|
|
* if its BUSY bit is cleared (thus high on PC).
|
|
|
|
|
*/
|
2007-04-02 21:29:53 +00:00
|
|
|
for (j_para = 0; j_para < MAXBUSY; j_para++) {
|
2010-12-09 21:25:42 +00:00
|
|
|
if ((port_in(p->port+1)) & BUSY)
|
2006-05-20 14:39:32 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2008-05-02 15:48:18 +00:00
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/* wait time of next WR */
|
|
|
|
|
for (j_para = 3; j_para < p->para_wait; j_para++)
|
2008-05-02 15:48:18 +00:00
|
|
|
port_in(p->port+1);
|
|
|
|
|
|
2006-05-20 14:39:32 +00:00
|
|
|
}
|
2006-12-08 18:06:59 +00:00
|
|
|
#endif
|
2006-05-20 14:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/**
|
|
|
|
|
* Open a serial port according to the settings in \c serialVFD_private_data.
|
|
|
|
|
* \param drvthis Pointer to driver
|
|
|
|
|
* \return -1 on error, 0 on success
|
|
|
|
|
*/
|
2006-05-20 14:39:32 +00:00
|
|
|
int
|
|
|
|
|
serialVFD_init_serial (Driver *drvthis)
|
|
|
|
|
{
|
|
|
|
|
PrivateData *p = drvthis->private_data;
|
|
|
|
|
struct termios portset;
|
|
|
|
|
|
|
|
|
|
/* Set up io port correctly, and open it...*/
|
|
|
|
|
debug( RPT_DEBUG, "%s: Opening device: %s", __FUNCTION__, p->device);
|
2007-04-02 21:29:53 +00:00
|
|
|
p->fd = open(p->device, O_RDWR | O_NOCTTY | O_NDELAY);
|
2006-05-20 14:39:32 +00:00
|
|
|
|
|
|
|
|
if (p->fd == -1) {
|
2007-06-17 10:39:49 +00:00
|
|
|
report(RPT_ERR, "%s: open() of %s failed (%s)", __FUNCTION__, p->device, strerror(errno));
|
2006-05-20 14:39:32 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-02 21:29:53 +00:00
|
|
|
tcgetattr(p->fd, &portset);
|
2006-05-20 14:39:32 +00:00
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/* We use RAW mode */
|
2006-05-20 14:39:32 +00:00
|
|
|
#ifdef HAVE_CFMAKERAW
|
2010-12-09 21:25:42 +00:00
|
|
|
/* The easy way */
|
2006-05-20 14:39:32 +00:00
|
|
|
cfmakeraw( &portset );
|
|
|
|
|
#else
|
2010-12-09 21:25:42 +00:00
|
|
|
/* The hard way */
|
2006-05-20 14:39:32 +00:00
|
|
|
portset.c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP
|
|
|
|
|
| INLCR | IGNCR | ICRNL | IXON );
|
|
|
|
|
portset.c_oflag &= ~OPOST;
|
|
|
|
|
portset.c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN );
|
|
|
|
|
portset.c_cflag &= ~( CSIZE | PARENB | CRTSCTS );
|
|
|
|
|
portset.c_cflag |= CS8 | CREAD | CLOCAL ;
|
|
|
|
|
#endif
|
|
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/* Set port speed */
|
2007-04-02 21:29:53 +00:00
|
|
|
cfsetospeed(&portset, p->speed);
|
|
|
|
|
cfsetispeed(&portset, B0);
|
2006-05-20 14:39:32 +00:00
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/* Do it... */
|
2007-04-02 21:29:53 +00:00
|
|
|
tcsetattr(p->fd, TCSANOW, &portset);
|
2006-05-20 14:39:32 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/**
|
|
|
|
|
* Open a parallel port according to the settings in \c serialVFD_private_data.
|
|
|
|
|
* \param drvthis Pointer to driver
|
|
|
|
|
* \return -1 on error, 0 on success
|
|
|
|
|
*/
|
2006-05-20 14:39:32 +00:00
|
|
|
int
|
|
|
|
|
serialVFD_init_parallel (Driver *drvthis)
|
|
|
|
|
{
|
|
|
|
|
PrivateData *p = drvthis->private_data;
|
2006-12-08 18:06:59 +00:00
|
|
|
#ifdef HAVE_PCSTYLE_LPT_CONTROL
|
2007-04-02 21:29:53 +00:00
|
|
|
debug(RPT_DEBUG, "%s: Opening parallelport at: 0x%X", __FUNCTION__, p->port);
|
|
|
|
|
if (port_access_multiple(p->port,3)) {
|
2007-06-17 10:39:49 +00:00
|
|
|
report(RPT_ERR, "%s: port_access_multiple() of 0x%X failed (%s)", __FUNCTION__, p->port, strerror(errno));
|
2006-05-20 14:39:32 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2006-12-08 18:06:59 +00:00
|
|
|
#else
|
2007-06-17 10:39:49 +00:00
|
|
|
report(RPT_ERR, "%s: LCDproc was compiled without PCstyle LPT support", __FUNCTION__);
|
2006-12-08 18:06:59 +00:00
|
|
|
return -1;
|
|
|
|
|
#endif
|
2006-05-20 14:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/**
|
|
|
|
|
* Close serial port.
|
|
|
|
|
* \param drvthis Pointer to driver
|
|
|
|
|
*/
|
2006-12-08 18:06:59 +00:00
|
|
|
void
|
|
|
|
|
serialVFD_close_serial (Driver *drvthis)
|
|
|
|
|
{
|
|
|
|
|
PrivateData *p = drvthis->private_data;
|
|
|
|
|
if (p->fd >= 0)
|
|
|
|
|
close(p->fd);
|
|
|
|
|
}
|
2006-05-20 14:39:32 +00:00
|
|
|
|
2010-12-09 21:25:42 +00:00
|
|
|
/**
|
|
|
|
|
* Close parallel port.
|
|
|
|
|
* \param drvthis Pointer to driver
|
|
|
|
|
*/
|
2006-12-08 18:06:59 +00:00
|
|
|
void
|
|
|
|
|
serialVFD_close_parallel (Driver *drvthis)
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_PCSTYLE_LPT_CONTROL
|
|
|
|
|
PrivateData *p = drvthis->private_data;
|
|
|
|
|
|
2007-04-02 21:29:53 +00:00
|
|
|
debug(RPT_DEBUG, "%s: Closing parallelport at: 0x%X", __FUNCTION__, p->port);
|
|
|
|
|
if (port_deny_multiple(p->port,3)) {
|
2007-06-17 10:39:49 +00:00
|
|
|
report(RPT_ERR, "%s: port_deny_multiple() of 0x%X failed (%s)", __FUNCTION__, p->port, strerror(errno));
|
2006-12-08 18:06:59 +00:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|