|
Packit |
d36e9b |
/*
|
|
Packit |
d36e9b |
* libieee1284 - IEEE 1284 library
|
|
Packit |
d36e9b |
* Copyright (C) 2001, 2002 Tim Waugh <twaugh@redhat.com>
|
|
Packit |
d36e9b |
*
|
|
Packit |
d36e9b |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
d36e9b |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
d36e9b |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
d36e9b |
* (at your option) any later version.
|
|
Packit |
d36e9b |
*
|
|
Packit |
d36e9b |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
d36e9b |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
d36e9b |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
d36e9b |
* GNU General Public License for more details.
|
|
Packit |
d36e9b |
*
|
|
Packit |
d36e9b |
* You should have received a copy of the GNU General Public License
|
|
Packit |
d36e9b |
* along with this program; if not, write to the Free Software
|
|
Packit |
d36e9b |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit |
d36e9b |
*/
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
#include <errno.h>
|
|
Packit |
d36e9b |
#include <fcntl.h>
|
|
Packit |
d36e9b |
#include <stdio.h>
|
|
Packit |
d36e9b |
#include <string.h>
|
|
Packit |
d36e9b |
#if !(defined __MINGW32__ || defined _MSC_VER)
|
|
Packit |
d36e9b |
#include <sys/ioctl.h>
|
|
Packit |
d36e9b |
#endif
|
|
Packit |
d36e9b |
#include <sys/stat.h>
|
|
Packit |
d36e9b |
#ifdef __unix__
|
|
Packit |
d36e9b |
#include <unistd.h>
|
|
Packit |
d36e9b |
#endif
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
#include "access.h"
|
|
Packit |
d36e9b |
#include "config.h"
|
|
Packit |
d36e9b |
#include "debug.h"
|
|
Packit |
d36e9b |
#include "default.h"
|
|
Packit |
d36e9b |
#include "delay.h"
|
|
Packit |
d36e9b |
#include "ieee1284.h"
|
|
Packit |
d36e9b |
#include "detect.h"
|
|
Packit |
d36e9b |
#include "parport.h"
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
#ifdef HAVE_LINUX
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
#include "ppdev.h"
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
struct ppdev_priv
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
struct timeval inactivity_timer;
|
|
Packit |
d36e9b |
int nonblock;
|
|
Packit |
d36e9b |
int current_flags;
|
|
Packit |
d36e9b |
};
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static void
|
|
Packit |
d36e9b |
find_capabilities (int fd, int *c)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int m;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
/* Work around a 2.4.x kernel bug by claiming the port for this
|
|
Packit |
d36e9b |
* even though we shouldn't have to. */
|
|
Packit |
d36e9b |
if (ioctl (fd, PPCLAIM))
|
|
Packit |
d36e9b |
goto guess;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (ioctl (fd, PPGETMODES, &m))
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
ioctl (fd, PPRELEASE);
|
|
Packit |
d36e9b |
guess:
|
|
Packit |
d36e9b |
*c |= CAP1284_ECP | CAP1284_ECPRLE | CAP1284_EPP;
|
|
Packit |
d36e9b |
return;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
ioctl (fd, PPRELEASE);
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (m & PARPORT_MODE_PCSPP)
|
|
Packit |
d36e9b |
*c |= CAP1284_RAW;
|
|
Packit |
d36e9b |
if (m & PARPORT_MODE_EPP)
|
|
Packit |
d36e9b |
*c |= CAP1284_EPP;
|
|
Packit |
d36e9b |
if (m & PARPORT_MODE_ECP)
|
|
Packit |
d36e9b |
*c |= CAP1284_ECP | CAP1284_ECPRLE;
|
|
Packit |
d36e9b |
if (m & PARPORT_MODE_DMA)
|
|
Packit |
d36e9b |
*c |= CAP1284_DMA;
|
|
Packit |
d36e9b |
if (!(m & PARPORT_MODE_TRISTATE))
|
|
Packit |
d36e9b |
*c &= ~(CAP1284_BYTE | CAP1284_ECPSWE);
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
init (struct parport *pport, int flags, int *capabilities)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
struct parport_internal *port = pport->priv;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (flags & ~F1284_EXCL)
|
|
Packit |
d36e9b |
return E1284_NOTAVAIL;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
port->access_priv = malloc (sizeof (struct ppdev_priv));
|
|
Packit |
d36e9b |
if (!port->access_priv)
|
|
Packit |
d36e9b |
return E1284_NOMEM;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
((struct ppdev_priv *)port->access_priv)->nonblock = 0;
|
|
Packit |
d36e9b |
((struct ppdev_priv *)port->access_priv)->current_flags = 0;
|
|
Packit |
d36e9b |
port->fd = open (port->device, O_RDWR | O_NOCTTY);
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
/* Retry with udev/devfs naming, if available */
|
|
Packit |
d36e9b |
if (port->fd < 0)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
if (port->udevice)
|
|
Packit |
d36e9b |
port->fd = open (port->udevice, O_RDWR | O_NOCTTY);
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (port->fd < 0)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
free (port->access_priv);
|
|
Packit |
d36e9b |
return E1284_INIT;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
else
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
pport->filename = port->udevice;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
else
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
pport->filename = port->device;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
port->current_mode = M1284_COMPAT;
|
|
Packit |
d36e9b |
if (flags & F1284_EXCL)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
if (ioctl (port->fd, PPEXCL))
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
close (port->fd);
|
|
Packit |
d36e9b |
free (port->access_priv);
|
|
Packit |
d36e9b |
return E1284_INIT;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (port->interrupt == -1)
|
|
Packit |
d36e9b |
/* Our implementation of do_nack_handshake relies on interrupts
|
|
Packit |
d36e9b |
* being available. They aren't, so use the default one instead. */
|
|
Packit |
d36e9b |
port->fn->do_nack_handshake = default_do_nack_handshake;
|
|
Packit |
d36e9b |
else if (capabilities)
|
|
Packit |
d36e9b |
*capabilities |= CAP1284_IRQ;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (capabilities)
|
|
Packit |
d36e9b |
find_capabilities (port->fd, capabilities);
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
return E1284_OK;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static void
|
|
Packit |
d36e9b |
cleanup (struct parport_internal *port)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
free (port->access_priv);
|
|
Packit |
d36e9b |
if (port->fd >= 0)
|
|
Packit |
d36e9b |
close (port->fd);
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
claim (struct parport_internal *port)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
debugprintf ("==> claim\n");
|
|
Packit |
d36e9b |
if (ioctl (port->fd, PPCLAIM))
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
debugprintf ("<== E1284_SYS\n");
|
|
Packit |
d36e9b |
return E1284_SYS;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
debugprintf ("<== E1284_OK\n");
|
|
Packit |
d36e9b |
return E1284_OK;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static void
|
|
Packit |
d36e9b |
release (struct parport_internal *port)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
ioctl (port->fd, PPRELEASE);
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
get_irq_fd (struct parport_internal *port)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
/* We _don't_ dup the file descriptor because reference counting is
|
|
Packit |
d36e9b |
* done at the port, and we don't want it to be valid after the port
|
|
Packit |
d36e9b |
* has been closed. */
|
|
Packit |
d36e9b |
return port->fd;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
clear_irq (struct parport_internal *port, unsigned int *count)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int c;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (ioctl (port->fd, PPCLRIRQ, &c))
|
|
Packit |
d36e9b |
return E1284_SYS;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (count)
|
|
Packit |
d36e9b |
*count = c;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
return E1284_OK;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
read_data (struct parport_internal *port)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
unsigned char reg;
|
|
Packit |
d36e9b |
if (ioctl (port->fd, PPRDATA, ®))
|
|
Packit |
d36e9b |
return E1284_NOTAVAIL;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
return reg;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static void
|
|
Packit |
d36e9b |
write_data (struct parport_internal *port, unsigned char reg)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
ioctl (port->fd, PPWDATA, ®);
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
read_status (struct parport_internal *port)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
unsigned char reg;
|
|
Packit |
d36e9b |
if (ioctl (port->fd, PPRSTATUS, ®))
|
|
Packit |
d36e9b |
return E1284_NOTAVAIL;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
return debug_display_status (reg ^ S1284_INVERTED);
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
read_control (struct parport_internal *port)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
unsigned char reg;
|
|
Packit |
d36e9b |
const unsigned char rm = (C1284_NSTROBE |
|
|
Packit |
d36e9b |
C1284_NAUTOFD |
|
|
Packit |
d36e9b |
C1284_NINIT |
|
|
Packit |
d36e9b |
C1284_NSELECTIN);
|
|
Packit |
d36e9b |
if (ioctl (port->fd, PPRCONTROL, ®))
|
|
Packit |
d36e9b |
return E1284_NOTAVAIL;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
return (reg ^ C1284_INVERTED) & rm;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
data_dir (struct parport_internal *port, int reverse)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
if (ioctl (port->fd, PPDATADIR, &reverse))
|
|
Packit |
d36e9b |
return E1284_SYS;
|
|
Packit |
d36e9b |
return E1284_OK;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static void
|
|
Packit |
d36e9b |
write_control (struct parport_internal *port, unsigned char reg)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
const unsigned char wm = (C1284_NSTROBE |
|
|
Packit |
d36e9b |
C1284_NAUTOFD |
|
|
Packit |
d36e9b |
C1284_NINIT |
|
|
Packit |
d36e9b |
C1284_NSELECTIN);
|
|
Packit |
d36e9b |
if (reg & 0x20)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
printf ("use ieee1284_data_dir to change data line direction!\n");
|
|
Packit |
d36e9b |
data_dir (port, 1);
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
reg &= wm;
|
|
Packit |
d36e9b |
reg ^= C1284_INVERTED;
|
|
Packit |
d36e9b |
ioctl (port->fd, PPWCONTROL, ®);
|
|
Packit |
d36e9b |
debug_display_control (reg);
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static void
|
|
Packit |
d36e9b |
frob_control (struct parport_internal *port,
|
|
Packit |
d36e9b |
unsigned char mask,
|
|
Packit |
d36e9b |
unsigned char val)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
struct ppdev_frob_struct ppfs;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (mask & 0x20)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
printf ("use ieee1284_data_dir to change data line direction!\n");
|
|
Packit |
d36e9b |
data_dir (port, val & 0x20);
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
/* Deal with inversion issues. */
|
|
Packit |
d36e9b |
ppfs.mask = mask;
|
|
Packit |
d36e9b |
ppfs.val = val ^ (mask & C1284_INVERTED);
|
|
Packit |
d36e9b |
debugprintf ("frob_control: ioctl(%d, PPFCONTROL, { mask:%#02x, val:%#02x }\n",
|
|
Packit |
d36e9b |
port->fd, ppfs.mask, ppfs.val);
|
|
Packit |
d36e9b |
ioctl (port->fd, PPFCONTROL, &ppfs);
|
|
Packit |
d36e9b |
debug_frob_control (mask, val);
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
wait_status (struct parport_internal *port,
|
|
Packit |
d36e9b |
unsigned char mask, unsigned char val,
|
|
Packit |
d36e9b |
struct timeval *timeout)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
/* This could be smarter: if we're just waiting for nAck, and we
|
|
Packit |
d36e9b |
* have interrutps to work with, we can just wait for an interrupt
|
|
Packit |
d36e9b |
* rather than polling. */
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
/* Simple-minded polling. TODO: Use David Paschal's method for this. */
|
|
Packit |
d36e9b |
struct timeval deadline, now;
|
|
Packit |
d36e9b |
gettimeofday (&deadline, NULL);
|
|
Packit |
d36e9b |
deadline.tv_sec += timeout->tv_sec;
|
|
Packit |
d36e9b |
deadline.tv_usec += timeout->tv_usec;
|
|
Packit |
d36e9b |
deadline.tv_sec += deadline.tv_usec / 1000000;
|
|
Packit |
d36e9b |
deadline.tv_usec %= 1000000;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
do
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
unsigned char st = debug_display_status (read_status (port));
|
|
Packit |
d36e9b |
if ((st & mask) == val)
|
|
Packit |
d36e9b |
return E1284_OK;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
delay (IO_POLL_DELAY);
|
|
Packit |
d36e9b |
gettimeofday (&now, NULL);
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
while (now.tv_sec < deadline.tv_sec ||
|
|
Packit |
d36e9b |
(now.tv_sec == deadline.tv_sec &&
|
|
Packit |
d36e9b |
now.tv_usec < deadline.tv_usec));
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
return E1284_TIMEDOUT;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
do_nack_handshake (struct parport_internal *port,
|
|
Packit |
d36e9b |
unsigned char ct_before,
|
|
Packit |
d36e9b |
unsigned char ct_after,
|
|
Packit |
d36e9b |
struct timeval *timeout)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
fd_set rfds;
|
|
Packit |
d36e9b |
int count;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (ioctl (port->fd, PPCLRIRQ, &count))
|
|
Packit |
d36e9b |
return E1284_NOTAVAIL;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (ioctl (port->fd, PPWCTLONIRQ, &ct_after))
|
|
Packit |
d36e9b |
return E1284_NOTAVAIL;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
write_control (port, ct_before);
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
FD_ZERO (&rfds);
|
|
Packit |
d36e9b |
FD_SET (port->fd, &rfds);
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
switch (select (port->fd + 1, &rfds, NULL, NULL, timeout))
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
case 0:
|
|
Packit |
d36e9b |
return E1284_TIMEDOUT;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
case -1:
|
|
Packit |
d36e9b |
return E1284_NOTAVAIL;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
ioctl (port->fd, PPCLRIRQ, &count);
|
|
Packit |
d36e9b |
if (count != 1)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
printf ("Multiple interrupts caught?\n");
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
return E1284_OK;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
which_mode (int mode, int flags)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int m;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (mode & (M1284_FLAG_DEVICEID | M1284_FLAG_EXT_LINK))
|
|
Packit |
d36e9b |
return mode;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
switch (mode)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
case M1284_NIBBLE:
|
|
Packit |
d36e9b |
case M1284_BYTE:
|
|
Packit |
d36e9b |
case M1284_COMPAT:
|
|
Packit |
d36e9b |
case M1284_ECPRLE:
|
|
Packit |
d36e9b |
case M1284_ECPSWE:
|
|
Packit |
d36e9b |
case M1284_EPPSWE:
|
|
Packit |
d36e9b |
m = mode;
|
|
Packit |
d36e9b |
break;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
case M1284_ECP:
|
|
Packit |
d36e9b |
if (flags & F1284_RLE)
|
|
Packit |
d36e9b |
m = IEEE1284_MODE_ECPRLE;
|
|
Packit |
d36e9b |
else if (flags & F1284_SWE)
|
|
Packit |
d36e9b |
m = IEEE1284_MODE_ECPSWE;
|
|
Packit |
d36e9b |
else if (flags & ~F1284_NONBLOCK)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
debugprintf ("flags is %x, but only F1284_RLE, F1284_SWE "
|
|
Packit |
d36e9b |
"and F1284_NONBLOCK are implemented\n", flags);
|
|
Packit |
d36e9b |
return E1284_NOTIMPL;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
else m = IEEE1284_MODE_ECP;
|
|
Packit |
d36e9b |
break;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
case M1284_EPP:
|
|
Packit |
d36e9b |
if (flags & F1284_SWE)
|
|
Packit |
d36e9b |
m = IEEE1284_MODE_EPPSWE;
|
|
Packit |
d36e9b |
else if (flags & ~(F1284_FASTEPP | F1284_NONBLOCK))
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
debugprintf ("flags is %x, but only F1284_SWE and F1284_NONBLOCK "
|
|
Packit |
d36e9b |
"are implemented\n", flags);
|
|
Packit |
d36e9b |
return E1284_NOTIMPL;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
else m = IEEE1284_MODE_EPP;
|
|
Packit |
d36e9b |
break;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
default:
|
|
Packit |
d36e9b |
debugprintf ("Unknown mode %x\n", mode);
|
|
Packit |
d36e9b |
return E1284_NOTIMPL;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
return m;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static ssize_t
|
|
Packit |
d36e9b |
translate_error_code (ssize_t e)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
if (e == -EAGAIN)
|
|
Packit |
d36e9b |
return E1284_TIMEDOUT;
|
|
Packit |
d36e9b |
if (e < 0)
|
|
Packit |
d36e9b |
return E1284_SYS;
|
|
Packit |
d36e9b |
return e;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
set_mode (struct parport_internal *port, int mode, int flags, int addr)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
struct ppdev_priv *priv = port->access_priv;
|
|
Packit |
d36e9b |
int m = which_mode (mode, flags);
|
|
Packit |
d36e9b |
int f = 0;
|
|
Packit |
d36e9b |
int ret = E1284_OK;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (m < 0)
|
|
Packit |
d36e9b |
return m;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
m |= addr ? IEEE1284_ADDR : IEEE1284_DATA;
|
|
Packit |
d36e9b |
if (port->current_mode != m)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
ret = translate_error_code (ioctl (port->fd, PPSETMODE, &m);;
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
port->current_mode = m;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (mode == M1284_EPP && (flags & F1284_FASTEPP))
|
|
Packit |
d36e9b |
f |= PP_FASTREAD | PP_FASTWRITE;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (priv->current_flags != f
|
|
Packit |
d36e9b |
&& mode == M1284_EPP) /* flags are only relevant for EPP right now */
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
ret = translate_error_code (ioctl (port->fd, PPSETFLAGS, &f);;
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
priv->current_flags = f;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
return ret;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
do_nonblock (struct parport_internal *port, int flags)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
struct ppdev_priv *priv = port->access_priv;
|
|
Packit |
d36e9b |
if ((flags & F1284_NONBLOCK) && !priv->nonblock)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
/* Enable O_NONBLOCK */
|
|
Packit |
d36e9b |
int f = fcntl (port->fd, F_GETFL);
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (f == -1)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
debugprintf ("do_nonblock: fcntl failed on F_GETFL\n");
|
|
Packit |
d36e9b |
return -1;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
f |= O_NONBLOCK;
|
|
Packit |
d36e9b |
if (fcntl (port->fd, F_SETFL, f))
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
debugprintf ("do_nonblock: fcntl failed on F_SETFL\n");
|
|
Packit |
d36e9b |
return -1;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
else if ((!(flags & F1284_NONBLOCK)) && priv->nonblock)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
/* Disable O_NONBLOCK */
|
|
Packit |
d36e9b |
int f = fcntl (port->fd, F_GETFL);
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (f == -1)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
debugprintf ("do_nonblock: fcntl failed on F_GETFL\n");
|
|
Packit |
d36e9b |
return -1;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
f &= O_NONBLOCK;
|
|
Packit |
d36e9b |
if (fcntl (port->fd, F_SETFL, f))
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
debugprintf ("do_nonblock: fcntl failed on F_SETFL\n");
|
|
Packit |
d36e9b |
return -1;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
return 0;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static int
|
|
Packit |
d36e9b |
negotiate (struct parport_internal *port, int mode)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int m = which_mode (mode, 0);
|
|
Packit |
d36e9b |
int ret;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
debugprintf ("==> negotiate (to %#02x)\n", mode);
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
ret = ioctl (port->fd, PPNEGOT, &m);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
port->current_mode = mode;
|
|
Packit |
d36e9b |
} else {
|
|
Packit |
d36e9b |
if (errno == EIO)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
debugprintf ("<== E1284_NEGFAILED\n");
|
|
Packit |
d36e9b |
return E1284_NEGFAILED;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
if (errno == ENXIO)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
debugprintf ("<== E1284_REJECTED\n");
|
|
Packit |
d36e9b |
return E1284_REJECTED;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
m = translate_error_code (ret);
|
|
Packit |
d36e9b |
debugprintf ("<== %d\n", m);
|
|
Packit |
d36e9b |
return m;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static void
|
|
Packit |
d36e9b |
terminate (struct parport_internal *port)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int m = IEEE1284_MODE_COMPAT;
|
|
Packit |
d36e9b |
if (!ioctl (port->fd, PPNEGOT, &m))
|
|
Packit |
d36e9b |
port->current_mode = IEEE1284_MODE_COMPAT;
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
/* Seems to be needed before negotiation. */
|
|
Packit |
d36e9b |
delay (IO_POLL_DELAY);
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static ssize_t
|
|
Packit |
d36e9b |
nibble_read (struct parport_internal *port, int flags,
|
|
Packit |
d36e9b |
char *buffer, size_t len)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int ret;
|
|
Packit |
d36e9b |
ret = do_nonblock (port, flags);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = set_mode (port, M1284_NIBBLE, 0, 0);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = translate_error_code (read (port->fd, buffer, len));
|
|
Packit |
d36e9b |
return ret;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static ssize_t
|
|
Packit |
d36e9b |
compat_write (struct parport_internal *port, int flags,
|
|
Packit |
d36e9b |
const char *buffer, size_t len)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int ret;
|
|
Packit |
d36e9b |
ret = do_nonblock (port, flags);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = set_mode (port, M1284_COMPAT, 0, 0);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = translate_error_code (write (port->fd, buffer, len));
|
|
Packit |
d36e9b |
return ret;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static ssize_t
|
|
Packit |
d36e9b |
byte_read (struct parport_internal *port, int flags,
|
|
Packit |
d36e9b |
char *buffer, size_t len)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int ret;
|
|
Packit |
d36e9b |
ret = do_nonblock (port, flags);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = set_mode (port, M1284_BYTE, 0, 0);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = translate_error_code (read (port->fd, buffer, len));
|
|
Packit |
d36e9b |
return ret;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static ssize_t
|
|
Packit |
d36e9b |
epp_read_data (struct parport_internal *port, int flags,
|
|
Packit |
d36e9b |
char *buffer, size_t len)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int ret;
|
|
Packit |
d36e9b |
ret = do_nonblock (port, flags);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = set_mode (port, M1284_EPP, flags, 0);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = translate_error_code (read (port->fd, buffer, len));
|
|
Packit |
d36e9b |
return ret;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static ssize_t
|
|
Packit |
d36e9b |
epp_write_data (struct parport_internal *port, int flags,
|
|
Packit |
d36e9b |
const char *buffer, size_t len)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int ret;
|
|
Packit |
d36e9b |
ret = do_nonblock (port, flags);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = set_mode (port, M1284_EPP, flags, 0);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = translate_error_code (write (port->fd, buffer, len));
|
|
Packit |
d36e9b |
return ret;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static ssize_t
|
|
Packit |
d36e9b |
epp_read_addr (struct parport_internal *port, int flags,
|
|
Packit |
d36e9b |
char *buffer, size_t len)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int ret;
|
|
Packit |
d36e9b |
ret = do_nonblock (port, flags);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = set_mode (port, M1284_EPP, flags, 1);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = translate_error_code (read (port->fd, buffer, len));
|
|
Packit |
d36e9b |
return ret;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static ssize_t
|
|
Packit |
d36e9b |
epp_write_addr (struct parport_internal *port, int flags,
|
|
Packit |
d36e9b |
const char *buffer, size_t len)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int ret;
|
|
Packit |
d36e9b |
ret = do_nonblock (port, flags);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = set_mode (port, M1284_EPP, flags, 1);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = translate_error_code (write (port->fd, buffer, len));
|
|
Packit |
d36e9b |
return ret;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static ssize_t
|
|
Packit |
d36e9b |
ecp_read_data (struct parport_internal *port, int flags,
|
|
Packit |
d36e9b |
char *buffer, size_t len)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int ret;
|
|
Packit |
d36e9b |
ret = do_nonblock (port, flags);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = set_mode (port, M1284_ECP, flags, 0);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = translate_error_code (read (port->fd, buffer, len));
|
|
Packit |
d36e9b |
return ret;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static ssize_t
|
|
Packit |
d36e9b |
ecp_write_data (struct parport_internal *port, int flags,
|
|
Packit |
d36e9b |
const char *buffer, size_t len)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int ret;
|
|
Packit |
d36e9b |
ret = do_nonblock (port, flags);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = set_mode (port, M1284_ECP, flags, 0);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = translate_error_code (write (port->fd, buffer, len));
|
|
Packit |
d36e9b |
return ret;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static ssize_t
|
|
Packit |
d36e9b |
ecp_write_addr (struct parport_internal *port, int flags,
|
|
Packit |
d36e9b |
const char *buffer, size_t len)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
int ret;
|
|
Packit |
d36e9b |
ret = do_nonblock (port, flags);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = set_mode (port, M1284_ECP, flags, 1);
|
|
Packit |
d36e9b |
if (!ret)
|
|
Packit |
d36e9b |
ret = translate_error_code (write (port->fd, buffer, len));
|
|
Packit |
d36e9b |
return ret;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
static struct timeval *
|
|
Packit |
d36e9b |
set_timeout (struct parport_internal *port, struct timeval *timeout)
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
struct ppdev_priv *priv = port->access_priv;
|
|
Packit |
d36e9b |
ioctl (port->fd, PPGETTIME, &priv->inactivity_timer);
|
|
Packit |
d36e9b |
ioctl (port->fd, PPSETTIME, timeout);
|
|
Packit |
d36e9b |
return &priv->inactivity_timer;
|
|
Packit |
d36e9b |
}
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
const struct parport_access_methods ppdev_access_methods =
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
init,
|
|
Packit |
d36e9b |
cleanup,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
claim,
|
|
Packit |
d36e9b |
release,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
NULL, /* inb */
|
|
Packit |
d36e9b |
NULL, /* outb */
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
get_irq_fd,
|
|
Packit |
d36e9b |
clear_irq,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
read_data,
|
|
Packit |
d36e9b |
write_data,
|
|
Packit |
d36e9b |
default_wait_data,
|
|
Packit |
d36e9b |
data_dir,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
read_status,
|
|
Packit |
d36e9b |
wait_status,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
read_control,
|
|
Packit |
d36e9b |
write_control,
|
|
Packit |
d36e9b |
frob_control,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
do_nack_handshake,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
negotiate,
|
|
Packit |
d36e9b |
terminate,
|
|
Packit |
d36e9b |
default_ecp_fwd_to_rev,
|
|
Packit |
d36e9b |
default_ecp_rev_to_fwd,
|
|
Packit |
d36e9b |
nibble_read,
|
|
Packit |
d36e9b |
compat_write,
|
|
Packit |
d36e9b |
byte_read,
|
|
Packit |
d36e9b |
epp_read_data,
|
|
Packit |
d36e9b |
epp_write_data,
|
|
Packit |
d36e9b |
epp_read_addr,
|
|
Packit |
d36e9b |
epp_write_addr,
|
|
Packit |
d36e9b |
ecp_read_data,
|
|
Packit |
d36e9b |
ecp_write_data,
|
|
Packit |
d36e9b |
default_ecp_read_addr,
|
|
Packit |
d36e9b |
ecp_write_addr,
|
|
Packit |
d36e9b |
set_timeout
|
|
Packit |
d36e9b |
};
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
/*
|
|
Packit |
d36e9b |
* Local Variables:
|
|
Packit |
d36e9b |
* eval: (c-set-style "gnu")
|
|
Packit |
d36e9b |
* End:
|
|
Packit |
d36e9b |
*/
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
#else /* Not Linux, no ppdev */
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
/* Null struct to keep the compiler happy */
|
|
Packit |
d36e9b |
const struct parport_access_methods ppdev_access_methods =
|
|
Packit |
d36e9b |
{
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
NULL, /* inb */
|
|
Packit |
d36e9b |
NULL, /* outb */
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL,
|
|
Packit |
d36e9b |
NULL
|
|
Packit |
d36e9b |
};
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
|
|
Packit |
d36e9b |
#endif /* HAVE_LINUX */
|