summaryrefslogtreecommitdiff
path: root/sanei/sanei_pa4s2.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-10-06 14:00:40 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-10-06 14:00:40 +0200
commit6e9c41a892ed0e0da326e0278b3221ce3f5713b8 (patch)
tree2e301d871bbeeb44aa57ff9cc070fcf3be484487 /sanei/sanei_pa4s2.c
Initial import of sane-backends version 1.0.24-1.2
Diffstat (limited to 'sanei/sanei_pa4s2.c')
-rw-r--r--sanei/sanei_pa4s2.c2103
1 files changed, 2103 insertions, 0 deletions
diff --git a/sanei/sanei_pa4s2.c b/sanei/sanei_pa4s2.c
new file mode 100644
index 0000000..8fe4260
--- /dev/null
+++ b/sanei/sanei_pa4s2.c
@@ -0,0 +1,2103 @@
+/* sane - Scanner Access Now Easy.
+ Copyright (C) 2000-2003 Jochen Eisinger <jochen.eisinger@gmx.net>
+ Copyright (C) 2003 James Perry (scsi_pp functions)
+ This file is part of the SANE package.
+
+ 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.
+
+ 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., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ As a special exception, the authors of SANE give permission for
+ additional uses of the libraries contained in this release of SANE.
+
+ The exception is that, if you link a SANE library with other files
+ to produce an executable, this does not by itself cause the
+ resulting executable to be covered by the GNU General Public
+ License. Your use of that executable is in no way restricted on
+ account of linking the SANE library code into it.
+
+ This exception does not, however, invalidate any other reasons why
+ the executable file might be covered by the GNU General Public
+ License.
+
+ If you submit changes to SANE to the maintainers to be included in
+ a subsequent release, you agree by submitting the changes that
+ those changes may be distributed with this exception intact.
+
+ If you write modifications of your own for SANE, it is your choice
+ whether to permit this exception to apply to your modifications.
+ If you do not wish that, delete this exception notice.
+
+ This file implements an interface for the Mustek PP chipset A4S2 */
+
+/* debug levels:
+ 0 - nothing
+ 1 - errors
+ 2 - warnings
+ 3 - things nice to know
+ 4 - code flow
+ 5 - detailed flow
+ 6 - everything
+
+ These debug levels can be set using the environment variable
+ SANE_DEBUG_SANEI_PA4S2 */
+
+#include "../include/sane/config.h"
+
+#define BACKEND_NAME sanei_pa4s2
+#include "../include/sane/sanei_backend.h" /* pick up compatibility defs */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined(HAVE_LIBIEEE1284)
+
+# include <ieee1284.h>
+
+#elif defined(ENABLE_PARPORT_DIRECTIO)
+
+# if defined(HAVE_SYS_IO_H)
+# if defined (__ICC) && __ICC >= 700
+# define __GNUC__ 2
+# endif
+# include <sys/io.h>
+# if defined (__ICC) && __ICC >= 700
+# undef __GNUC__
+# elif defined(__ICC) && defined(HAVE_ASM_IO_H)
+# include <asm/io.h>
+# endif
+# elif defined(HAVE_ASM_IO_H)
+# include <asm/io.h> /* ugly, but backwards compatible */
+# elif defined(HAVE_SYS_HW_H)
+# include <sys/hw.h>
+# elif defined(__i386__) && ( defined (__GNUC__) || defined (__ICC) )
+
+static __inline__ void
+outb (u_char value, u_long port)
+{
+ __asm__ __volatile__ ("outb %0,%1"::"a" (value), "d" ((u_short) port));
+}
+
+static __inline__ u_char
+inb (u_long port)
+{
+ u_char value;
+
+ __asm__ __volatile__ ("inb %1,%0":"=a" (value):"d" ((u_short) port));
+ return value;
+}
+
+# else
+# define IO_SUPPORT_MISSING
+# endif
+
+#else
+
+# define IO_SUPPORT_MISSING
+
+#endif /* HAVE_LIBIEEE1284 */
+
+#include "../include/sane/sane.h"
+#include "../include/sane/sanei.h"
+#include "../include/sane/sanei_pa4s2.h"
+
+
+#ifdef NDEBUG
+#define DBG_INIT() /* basically, this is already done in sanei_debug.h... */
+
+#define TEST_DBG_INIT()
+
+#else /* !NDEBUG */
+
+static int sanei_pa4s2_dbg_init_called = SANE_FALSE;
+
+#if (!defined __GNUC__ || __GNUC__ < 2 || \
+ __GNUC_MINOR__ < (defined __cplusplus ? 6 : 4))
+
+#define TEST_DBG_INIT() if (sanei_pa4s2_dbg_init_called == SANE_FALSE) \
+ { \
+ DBG_INIT(); \
+ DBG(6, "sanei_pa4s2: interface called for" \
+ " the first time\n"); \
+ sanei_pa4s2_dbg_init_called = SANE_TRUE; \
+ }
+#else
+
+#define TEST_DBG_INIT() if (sanei_pa4s2_dbg_init_called == SANE_FALSE) \
+ { \
+ DBG_INIT(); \
+ DBG(6, "%s: interface called for" \
+ " the first time\n", __PRETTY_FUNCTION__); \
+ sanei_pa4s2_dbg_init_called = SANE_TRUE; \
+ }
+
+#endif
+
+#endif /* NDEBUG */
+
+#if defined(STDC_HEADERS)
+# include <errno.h>
+# include <stdio.h>
+# include <stdlib.h>
+#endif
+#if defined(HAVE_STRING_H)
+# include <string.h>
+#elif defined(HAVE_STRINGS_H)
+# include <strings.h>
+#endif
+#if defined(HAVE_SYS_TYPES_H)
+# include <sys/types.h>
+#endif
+
+#include "../include/sane/saneopts.h"
+
+
+#if (defined (HAVE_IOPERM) || defined (HAVE_LIBIEEE1284)) && !defined (IO_SUPPORT_MISSING)
+
+#if defined(STDC_HEADERS)
+# include <errno.h>
+# include <stdio.h>
+# include <stdlib.h>
+#endif
+#if defined(HAVE_STRING_H)
+# include <string.h>
+#elif defined(HAVE_STRINGS_H)
+# include <strings.h>
+#endif
+#if defined(HAVE_SYS_TYPES_H)
+# include <sys/types.h>
+#endif
+
+#include "../include/sane/saneopts.h"
+
+#define PA4S2_MODE_NIB 0
+#define PA4S2_MODE_UNI 1
+#define PA4S2_MODE_EPP 2
+
+#define PA4S2_ASIC_ID_1013 0xA8
+#define PA4S2_ASIC_ID_1015 0xA5
+#define PA4S2_ASIC_ID_1505 0xA2
+
+
+typedef struct
+ {
+#ifndef HAVE_LIBIEEE1284
+ const char name[6];
+ u_long base; /* i/o base address */
+#endif
+ u_int in_use; /* port in use? */
+ u_int enabled; /* port enabled? */
+ u_int mode; /* protocoll */
+ u_char prelock[3]; /* state of port */
+#ifdef HAVE_LIBIEEE1284
+ int caps;
+#endif
+ }
+PortRec, *Port;
+
+#if defined (HAVE_LIBIEEE1284)
+
+static struct parport_list pplist;
+static PortRec *port;
+
+#else
+
+static PortRec port[] =
+{
+ {"0x378", 0x378, SANE_FALSE, SANE_FALSE, PA4S2_MODE_NIB,
+ {0, 0, 0}},
+ {"0x278", 0x278, SANE_FALSE, SANE_FALSE, PA4S2_MODE_NIB,
+ {0, 0, 0}},
+ {"0x3BC", 0x3BC, SANE_FALSE, SANE_FALSE, PA4S2_MODE_NIB,
+ {0, 0, 0}}
+};
+
+#endif
+
+static u_int sanei_pa4s2_interface_options = SANEI_PA4S2_OPT_DEFAULT;
+
+extern int setuid (uid_t); /* should also be in unistd.h */
+
+static int pa4s2_open (const char *dev, SANE_Status * status);
+static void pa4s2_readbegin_epp (int fd, u_char reg);
+static u_char pa4s2_readbyte_epp (int fd);
+static void pa4s2_readend_epp (int fd);
+static void pa4s2_readbegin_uni (int fd, u_char reg);
+static u_char pa4s2_readbyte_uni (int fd);
+static void pa4s2_readend_uni (int fd);
+static void pa4s2_readbegin_nib (int fd, u_char reg);
+static u_char pa4s2_readbyte_nib (int fd);
+static void pa4s2_readend_nib (int fd);
+static void pa4s2_writebyte_any (int fd, u_char reg, u_char val);
+static int pa4s2_enable (int fd, u_char * prelock);
+static int pa4s2_disable (int fd, u_char * prelock);
+static int pa4s2_close (int fd, SANE_Status * status);
+
+#if defined (HAVE_LIBIEEE1284)
+
+static const char * pa4s2_libieee1284_errorstr(int error)
+{
+
+ switch (error)
+ {
+
+ case E1284_OK:
+ return "Everything went fine";
+
+ case E1284_NOTIMPL:
+ return "Not implemented in libieee1284";
+
+ case E1284_NOTAVAIL:
+ return "Not available on this system";
+
+ case E1284_TIMEDOUT:
+ return "Operation timed out";
+
+ case E1284_REJECTED:
+ return "IEEE 1284 negotiation rejected";
+
+ case E1284_NEGFAILED:
+ return "Negotiation went wrong";
+
+ case E1284_NOMEM:
+ return "No memory left";
+
+ case E1284_INIT:
+ return "Error initializing port";
+
+ case E1284_SYS:
+ return "Error interfacing system";
+
+ case E1284_NOID:
+ return "No IEEE 1284 ID available";
+
+ case E1284_INVALIDPORT:
+ return "Invalid port";
+
+ default:
+ return "Unknown error";
+
+ }
+}
+
+#endif
+
+static int
+pa4s2_init (SANE_Status *status)
+{
+ static int first_time = SANE_TRUE;
+#if defined (HAVE_LIBIEEE1284)
+ int result, n;
+#endif
+
+ DBG (6, "pa4s2_init: static int first_time = %u\n", first_time);
+
+ if (first_time == SANE_FALSE)
+ {
+ DBG (5, "pa4s2_init: sanei already initalized\n");
+ status = SANE_STATUS_GOOD;
+ return 0;
+ }
+
+ DBG (5, "pa4s2_init: called for the first time\n");
+
+ first_time = SANE_FALSE;
+
+#if defined (HAVE_LIBIEEE1284)
+
+ DBG (4, "pa4s2_init: initializing libieee1284\n");
+ result = ieee1284_find_ports (&pplist, 0);
+
+ if (result)
+ {
+ DBG (1, "pa4s2_init: initializing IEEE 1284 failed (%s)\n",
+ pa4s2_libieee1284_errorstr (result));
+ first_time = SANE_TRUE;
+ *status = SANE_STATUS_INVAL;
+ return -1;
+ }
+
+ DBG (3, "pa4s2_init: %d ports reported by IEEE 1284 library\n", pplist.portc);
+
+ for (n=0; n<pplist.portc; n++)
+ DBG (6, "pa4s2_init: port %d is `%s`\n", n, pplist.portv[n]->name);
+
+
+ DBG (6, "pa4s2_init: allocating port list\n");
+ if ((port = calloc(pplist.portc, sizeof(PortRec))) == NULL)
+ {
+ DBG (1, "pa4s2_init: not enough free memory\n");
+ ieee1284_free_ports(&pplist);
+ first_time = SANE_TRUE;
+ *status = SANE_STATUS_NO_MEM;
+ return -1;
+ }
+
+#else
+
+ DBG (4, "pa4s2_init: trying to setuid root\n");
+
+ if (0 > setuid (0))
+ {
+
+ DBG (1, "pa4s2_init: setuid failed: errno = %d\n", errno);
+ DBG (5, "pa4s2_init: returning SANE_STATUS_INVAL\n");
+
+ *status = SANE_STATUS_INVAL;
+ first_time = SANE_TRUE;
+ return -1;
+
+ }
+
+ DBG (3, "pa4s2_init: the application is now root\n");
+ DBG (3, "pa4s2_init: this is a high security risk...\n");
+
+ DBG (6, "pa4s2_init: ... you'd better start praying\n");
+
+ /* PS: no, i don't trust myself either */
+
+ /* PPS: i'd try rsbac or similar if i were you */
+
+#endif
+
+ DBG (5, "pa4s2_init: initialized successfully\n");
+ *status = SANE_STATUS_GOOD;
+ return 0;
+}
+
+static int
+pa4s2_open (const char *dev, SANE_Status * status)
+{
+
+ int n, result;
+#if !defined (HAVE_LIBIEEE1284)
+ u_long base;
+#endif
+
+ DBG (4, "pa4s2_open: trying to attach dev `%s`\n", dev);
+
+ if ((result = pa4s2_init(status)) != 0)
+ {
+
+ DBG (1, "pa4s2_open: failed to initialize\n");
+ return result;
+ }
+
+#if !defined (HAVE_LIBIEEE1284)
+
+ {
+ char *end;
+
+ DBG (5, "pa4s2_open: reading port number\n");
+
+ base = strtol (dev, &end, 0);
+
+ if ((end == dev) || (*end != '\0'))
+ {
+
+ DBG (1, "pa4s2_open: `%s` is not a valid port number\n", dev);
+ DBG (6, "pa4s2_open: the part I did not understand was ...`%s`\n", end);
+ DBG (5, "pa4s2_open: returning SANE_STATUS_INVAL\n");
+
+ *status = SANE_STATUS_INVAL;
+
+ return -1;
+
+ }
+
+ }
+
+ DBG (6, "pa4s2_open: read port number 0x%03lx\n", base);
+
+ if (base == 0)
+ {
+
+ DBG (1, "pa4s2_open: 0x%03lx is not a valid base address\n", base);
+ DBG (5, "pa4s2_open: returning SANE_STATUS_INVAL\n");
+
+ *status = SANE_STATUS_INVAL;
+ return -1;
+
+ }
+#endif
+
+ DBG (5, "pa4s2_open: looking up port in list\n");
+
+#if defined (HAVE_LIBIEEE1284)
+
+ for (n = 0; n < pplist.portc; n++)
+ if (!strcmp(pplist.portv[n]->name, dev))
+ break;
+
+ if (pplist.portc <= n)
+ {
+ DBG (1, "pa4s2_open: `%s` is not a valid device name\n", dev);
+ DBG (5, "pa4s2_open: returning SANE_STATUS_INVAL\n");
+
+ *status = SANE_STATUS_INVAL;
+ return -1;
+ }
+
+#else
+
+ for (n = 0; n < NELEMS (port); n++)
+ if (port[n].base == base)
+ break;
+
+ if (NELEMS (port) <= n)
+ {
+
+ DBG (1, "pa4s2_open: 0x%03lx is not a valid base address\n",
+ base);
+ DBG (5, "pa4s2_open: returning SANE_STATUS_INVAL\n");
+
+ *status = SANE_STATUS_INVAL;
+ return -1;
+ }
+
+#endif
+
+ DBG (6, "pa4s2_open: port is in list at port[%d]\n", n);
+
+ if (port[n].in_use == SANE_TRUE)
+ {
+
+#if defined (HAVE_LIBIEEE1284)
+ DBG (1, "pa4s2_open: device `%s` is already in use\n", dev);
+#else
+ DBG (1, "pa4s2_open: port 0x%03lx is already in use\n", base);
+#endif
+ DBG (5, "pa4s2_open: returning SANE_STATUS_DEVICE_BUSY\n");
+
+ *status = SANE_STATUS_DEVICE_BUSY;
+ return -1;
+
+ }
+
+ DBG (5, "pa4s2_open: setting up port data\n");
+
+#if defined (HAVE_LIBIEEE1284)
+ DBG (6, "pa4s2_open: name=%s in_use=SANE_TRUE\n", dev);
+#else
+ DBG (6, "pa4s2_open: base=0x%03lx in_use=SANE_TRUE\n", base);
+#endif
+ DBG (6, "pa4s2_open: enabled=SANE_FALSE mode=PA4S2_MODE_NIB\n");
+ port[n].in_use = SANE_TRUE;
+ port[n].enabled = SANE_FALSE;
+ port[n].mode = PA4S2_MODE_NIB;
+
+
+#if defined (HAVE_LIBIEEE1284)
+
+ DBG (5, "pa4s2_open: opening device\n");
+ result = ieee1284_open (pplist.portv[n], 0, &port[n].caps);
+
+ if (result)
+ {
+ DBG (1, "pa4s2_open: could not open device `%s` (%s)\n",
+ dev, pa4s2_libieee1284_errorstr (result));
+ port[n].in_use = SANE_FALSE;
+ DBG (6, "pa4s2_open: marking port %d as unused\n", n);
+ *status = SANE_STATUS_ACCESS_DENIED;
+ return -1;
+ }
+
+#else
+
+ DBG (5, "pa4s2_open: getting io permissions\n");
+
+ /* TODO: insert FreeBSD compatible code here */
+
+ if (ioperm (port[n].base, 5, 1))
+ {
+
+ DBG (1, "pa4s2_open: cannot get io privilege for port 0x%03lx\n",
+ port[n].base);
+
+
+ DBG (5, "pa4s2_open: marking port[%d] as unused\n", n);
+ port[n].in_use = SANE_FALSE;
+
+ DBG (5, "pa4s2_open: returning SANE_STATUS_IO_ERROR\n");
+ *status = SANE_STATUS_IO_ERROR;
+ return -1;
+
+ }
+#endif
+
+ DBG (3, "pa4s2_open: device `%s` opened...\n", dev);
+
+ DBG (5, "pa4s2_open: returning SANE_STATUS_GOOD\n");
+ *status = SANE_STATUS_GOOD;
+
+ DBG (4, "pa4s2_open: open dev `%s` as fd %u\n", dev, n);
+
+ return n;
+
+}
+
+#if defined(HAVE_LIBIEEE1284)
+
+
+#define inbyte0(fd) ieee1284_read_data(pplist.portv[fd]);
+#define inbyte1(fd) (ieee1284_read_status(pplist.portv[fd]) ^ S1284_INVERTED)
+#define inbyte2(fd) (ieee1284_read_control(pplist.portv[fd]) ^ C1284_INVERTED)
+static u_char inbyte4(int fd)
+{
+ char val;
+ ieee1284_epp_read_data(pplist.portv[fd], 0, &val, 1);
+ return (u_char)val;
+}
+
+#define outbyte0(fd,val) ieee1284_write_data(pplist.portv[fd], val)
+#define outbyte1(fd,val) /* ieee1284_write_status(pplist.portv[fd], (val) ^ S1284_INVERTED) */
+#define outbyte2(fd,val) ieee1284_write_control(pplist.portv[fd], (val) ^ C1284_INVERTED)
+
+static void outbyte3(int fd, u_char val)
+{
+ ieee1284_epp_write_addr (pplist.portv[fd], 0, (char *)&val, 1);
+}
+
+#else
+
+#define inbyte0(fd) inb(port[fd].base)
+#define inbyte1(fd) inb(port[fd].base + 1)
+#define inbyte2(fd) inb(port[fd].base + 2)
+#define inbyte4(fd) inb(port[fd].base + 4)
+
+#define outbyte0(fd,val) outb(val, port[fd].base)
+#define outbyte1(fd,val) outb(val, port[fd].base + 1)
+#define outbyte2(fd,val) outb(val, port[fd].base + 2)
+#define outbyte3(fd,val) outb(val, port[fd].base + 3)
+
+#endif
+
+
+static void
+pa4s2_readbegin_epp (int fd, u_char reg)
+{
+
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "pa4s2_readbegin_epp: selecting register %u at '%s'\n",
+ (int) reg, pplist.portv[fd]->name);
+#else
+ DBG (6, "pa4s2_readbegin_epp: selecting register %u at 0x%03lx\n",
+ (int) reg, port[fd].base);
+#endif
+
+ outbyte0 (fd, 0x20);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x06);
+ outbyte2 (fd, 0x04);
+ outbyte3 (fd, reg + 0x18);
+
+}
+
+static u_char
+pa4s2_readbyte_epp (int fd)
+{
+
+ u_char val = inbyte4 (fd);
+
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "pa4s2_readbyte_epp: reading value 0x%02x from '%s'\n",
+ (int) val, pplist.portv[fd]->name);
+#else
+ DBG (6, "pa4s2_readbyte_epp: reading value 0x%02x at 0x%03lx\n",
+ (int) val, port[fd].base);
+#endif
+
+ return val;
+
+}
+
+static void
+pa4s2_readend_epp (int fd)
+{
+
+ DBG (6, "pa4s2_readend_epp: end of reading sequence\n");
+
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x00);
+ outbyte2 (fd, 0x04);
+
+}
+
+static void
+pa4s2_readbegin_uni (int fd, u_char reg)
+{
+
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "pa4s2_readbegin_uni: selecting register %u for '%s'\n",
+ (int) reg, pplist.portv[fd]->name);
+#else
+ DBG (6, "pa4s2_readbegin_uni: selecting register %u at 0x%03lx\n",
+ (int) reg, port[fd].base);
+#endif
+
+ outbyte0 (fd, reg | 0x58);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x06);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x04);
+
+}
+
+static u_char
+pa4s2_readbyte_uni (int fd)
+{
+ u_char val;
+
+ outbyte2 (fd, 0x05);
+ val = inbyte2(fd);
+ val <<= 4;
+ val &= 0xE0;
+ val |= (inbyte1(fd) >> 3);
+ outbyte2 (fd, 0x04);
+
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "pa4s2_readbyte_uni: reading value 0x%02x from '%s'\n",
+ (int) val, pplist.portv[fd]->name);
+#else
+ DBG (6, "pa4s2_readbyte_uni: reading value 0x%02x at 0x%03lx\n",
+ (int) val, port[fd].base);
+#endif
+
+ return val;
+}
+
+static void
+pa4s2_readend_uni (int fd)
+{
+
+ DBG (6, "pa4s2_readend_uni: end of reading sequence for fd %d\n", fd);
+
+}
+
+static void
+pa4s2_readbegin_nib (int fd, u_char reg)
+{
+
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "pa4s2_readbegin_nib: selecting register %u at '%s'\n",
+ (int) reg, pplist.portv[fd]->name);
+#else
+ DBG (6, "pa4s2_readbegin_nib: selecting register %u at 0x%03lx\n",
+ (int) reg, port[fd].base);
+#endif
+
+
+ outbyte0 (fd, reg | 0x18);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x06);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x04);
+
+}
+
+static u_char
+pa4s2_readbyte_nib (int fd)
+{
+
+ u_char val;
+
+ outbyte2 (fd, 0x05);
+ val = inbyte1(fd);
+ val >>= 4;
+ outbyte0 (fd, 0x58);
+ val |= inbyte1(fd) & 0xF0;
+ val ^= 0x88;
+ outbyte0 (fd, 0x00);
+ outbyte2 (fd, 0x04);
+
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "pa4s2_readbyte_nib: reading value 0x%02x from '%s'\n",
+ (int) val, pplist.portv[fd]->name);
+#else
+ DBG (6, "pa4s2_readbyte_nib: reading value 0x%02x at 0x%03lx\n",
+ (int) val, port[fd].base);
+#endif
+
+ return val;
+
+}
+
+static void
+pa4s2_readend_nib (int fd)
+{
+ DBG (6, "pa4s2_readend_nib: end of reading sequence for fd %d\n", fd);
+}
+
+static void
+pa4s2_writebyte_any (int fd, u_char reg, u_char val)
+{
+
+ /* somebody from Mustek asked me once, why I was writing the same
+ value repeatedly to a port. Well, actually I don't know, it just
+ works. Maybe the repeated writes could be replaced by appropriate
+ delays or even left out completly.
+ */
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "pa4s2_writebyte_any: writing value 0x%02x"
+ " in reg %u to '%s'\n", (int) val, (int) reg, pplist.portv[fd]->name);
+#else
+ DBG (6, "pa4s2_writebyte_any: writing value 0x%02x"
+ " in reg %u at 0x%03lx\n", (int) val, (int) reg, port[fd].base);
+#endif
+
+ outbyte0 (fd, reg | 0x10);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x06);
+ outbyte2 (fd, 0x06);
+ outbyte2 (fd, 0x06);
+ outbyte2 (fd, 0x06);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x04);
+ outbyte0 (fd, val);
+ outbyte2 (fd, 0x05);
+ outbyte2 (fd, 0x05);
+ outbyte2 (fd, 0x05);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x04);
+}
+
+static int
+pa4s2_enable (int fd, u_char * prelock)
+{
+#if defined (HAVE_LIBIEEE1284)
+ int result;
+ result = ieee1284_claim (pplist.portv[fd]);
+
+ if (result)
+ {
+ DBG (1, "pa4s2_enable: failed to claim the port (%s)\n",
+ pa4s2_libieee1284_errorstr(result));
+ return -1;
+ }
+#endif
+
+ prelock[0] = inbyte0 (fd);
+ prelock[1] = inbyte1 (fd);
+ prelock[2] = inbyte2 (fd);
+ outbyte2 (fd, (prelock[2] & 0x0F) | 0x04);
+
+ DBG (6, "pa4s2_enable: prelock[] = {0x%02x, 0x%02x, 0x%02x}\n",
+ (int) prelock[0], (int) prelock[1], (int) prelock[2]);
+
+ outbyte0 (fd, 0x15);
+ outbyte0 (fd, 0x95);
+ outbyte0 (fd, 0x35);
+ outbyte0 (fd, 0xB5);
+ outbyte0 (fd, 0x55);
+ outbyte0 (fd, 0xD5);
+ outbyte0 (fd, 0x75);
+ outbyte0 (fd, 0xF5);
+ outbyte0 (fd, 0x01);
+ outbyte0 (fd, 0x81);
+
+ return 0;
+}
+
+static int
+pa4s2_disable (int fd, u_char * prelock)
+{
+
+ if ((sanei_pa4s2_interface_options & SANEI_PA4S2_OPT_ALT_LOCK) != 0)
+ {
+
+ DBG (6, "pa4s2_disable: using alternative command set\n");
+
+ outbyte0 (fd, 0x00);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x06);
+ outbyte2 (fd, 0x04);
+
+ }
+
+ outbyte2 (fd, prelock[2] & 0x0F);
+
+ outbyte0 (fd, 0x15);
+ outbyte0 (fd, 0x95);
+ outbyte0 (fd, 0x35);
+ outbyte0 (fd, 0xB5);
+ outbyte0 (fd, 0x55);
+ outbyte0 (fd, 0xD5);
+ outbyte0 (fd, 0x75);
+ outbyte0 (fd, 0xF5);
+ outbyte0 (fd, 0x00);
+ outbyte0 (fd, 0x80);
+
+ outbyte0 (fd, prelock[0]);
+ outbyte1 (fd, prelock[1]);
+ outbyte2 (fd, prelock[2]);
+
+#if defined(HAVE_LIBIEEE1284)
+ ieee1284_release (pplist.portv[fd]);
+#endif
+
+ DBG (6, "pa4s2_disable: state restored\n");
+
+ return 0;
+
+}
+
+static int
+pa4s2_close (int fd, SANE_Status * status)
+{
+#if defined(HAVE_LIBIEEE1284)
+ int result;
+#endif
+ DBG (4, "pa4s2_close: fd=%d\n", fd);
+
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "pa4s2_close: this is port '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (6, "pa4s2_close: this is port 0x%03lx\n", port[fd].base);
+#endif
+
+ DBG (5, "pa4s2_close: checking whether port is enabled\n");
+
+ if (port[fd].enabled == SANE_TRUE)
+ {
+
+ DBG (6, "pa4s2_close: disabling port\n");
+ pa4s2_disable (fd, port[fd].prelock);
+
+ }
+
+ DBG (5, "pa4s2_close: trying to free io port\n");
+#if defined(HAVE_LIBIEEE1284)
+ if ((result = ieee1284_close(pplist.portv[fd])) < 0)
+#else
+ if (ioperm (port[fd].base, 5, 0))
+#endif
+ {
+
+#if defined(HAVE_LIBIEEE1284)
+ DBG (1, "pa4s2_close: can't free port '%s' (%s)\n",
+ pplist.portv[fd]->name, pa4s2_libieee1284_errorstr(result));
+#else
+ DBG (1, "pa4s2_close: can't free port 0x%03lx\n", port[fd].base);
+#endif
+
+ DBG (5, "pa4s2_close: returning SANE_STATUS_IO_ERROR\n");
+ *status = SANE_STATUS_IO_ERROR;
+ return -1;
+
+ }
+
+ DBG (5, "pa4s2_close: marking port as unused\n");
+
+ port[fd].in_use = SANE_FALSE;
+
+ DBG (5, "pa4s2_close: returning SANE_STATUS_GOOD\n");
+
+ *status = SANE_STATUS_GOOD;
+
+ return 0;
+
+}
+
+const char **
+sanei_pa4s2_devices()
+{
+
+ SANE_Status status;
+ int n;
+ const char **devices;
+
+ TEST_DBG_INIT();
+
+ DBG (4, "sanei_pa4s2_devices: invoked\n");
+
+ if ((n = pa4s2_init(&status)) != 0)
+ {
+
+ DBG (1, "sanei_pa4s2_devices: failed to initialize (%s)\n",
+ sane_strstatus(status));
+ return calloc(1, sizeof(char *));
+ }
+
+#if defined(HAVE_LIBIEEE1284)
+
+ if ((devices = calloc((pplist.portc + 1), sizeof(char *))) == NULL)
+ {
+ DBG (2, "sanei_pa4s2_devices: not enough free memory\n");
+ return calloc(1, sizeof(char *));
+ }
+
+ for (n=0; n<pplist.portc; n++)
+ devices[n] = pplist.portv[n]->name;
+
+#else
+
+ if ((devices = calloc((NELEMS (port) + 1), sizeof(char *))) == NULL)
+ {
+ DBG (2, "sanei_pa4s2_devices: not enough free memory\n");
+ return calloc(1, sizeof(char *));
+ }
+
+ for (n=0 ; n<NELEMS (port) ; n++)
+ devices[n] = (char *)port[n].name;
+#endif
+
+ return devices;
+}
+
+/*
+ * Needed for SCSI-over-parallel scanners (Paragon 600 II EP)
+ */
+SANE_Status
+sanei_pa4s2_scsi_pp_get_status(int fd, u_char *status)
+{
+ u_char stat;
+
+ TEST_DBG_INIT ();
+
+ DBG (6, "sanei_pa4s2_scsi_pp_get_status: called for fd %d\n",
+ fd);
+
+#if defined(HAVE_LIBIEEE1284)
+ if ((fd < 0) || (fd >= pplist.portc))
+#else
+ if ((fd < 0) || (fd >= NELEMS (port)))
+#endif
+ {
+
+ DBG (2, "sanei_pa4s2_scsi_pp_get_status: invalid fd %d\n", fd);
+ DBG (6, "sanei_pa4s2_scsi_pp_get_status: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].in_use == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_scsi_pp_get_status: port is not in use\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (4, "sanei_pa4s2_scsi_pp_get_status: port is '%s'\n",
+ pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_scsi_pp_get_status: port is 0x%03lx\n",
+ port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_scsi_pp_get_status: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].enabled == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_scsi_pp_get_status: port is not enabled\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (4, "sanei_pa4s2_scsi_pp_get_status: port is '%s'\n",
+ pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_scsi_pp_get_status: port is 0x%03lx\n",
+ port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_scsi_pp_get_status: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ outbyte2 (fd, 0x4);
+ stat = inbyte1 (fd)^0x80;
+ *status = (stat&0x2f)|((stat&0x10)<<2)|((stat&0x40)<<1)|((stat&0x80)>>3);
+ DBG (5, "sanei_pa4s2_scsi_pp_get_status: status=0x%02X\n", *status);
+ DBG (6, "sanei_pa4s2_scsi_pp_get_status: returning SANE_STATUS_GOOD\n");
+
+ return SANE_STATUS_GOOD;
+}
+
+/*
+ * SCSI-over-parallel scanners need this done when a register is
+ * selected
+ */
+SANE_Status
+sanei_pa4s2_scsi_pp_reg_select (int fd, int reg)
+{
+ TEST_DBG_INIT ();
+
+#if defined(HAVE_LIBIEEE1284)
+ if ((fd < 0) || (fd >= pplist.portc))
+#else
+ if ((fd < 0) || (fd >= NELEMS (port)))
+#endif
+ {
+
+ DBG (2, "sanei_pa4s2_scsi_pp_reg_select: invalid fd %d\n", fd);
+ DBG (6, "sanei_pa4s2_scsi_pp_reg_select: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].in_use == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_scsi_pp_reg_select: port is not in use\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (4, "sanei_pa4s2_scsi_pp_get_status: port is '%s'\n",
+ pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_scsi_pp_get_status: port is 0x%03lx\n",
+ port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_scsi_pp_reg_select: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].enabled == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_scsi_pp_reg_select: port is not enabled\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (4, "sanei_pa4s2_scsi_pp_get_status: port is '%s'\n",
+ pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_scsi_pp_get_status: port is 0x%03lx\n",
+ port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_scsi_pp_reg_select: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "sanei_pa4s2_scsi_pp_reg_select: selecting register %u at port '%s'\n",
+ (int) reg, pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_scsi_pp_reg_select: selecting register %u at 0x%03lx\n",
+ (int) reg, (u_long)port[fd].base);
+#endif
+
+ outbyte0 (fd, reg | 0x58);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x06);
+ outbyte2 (fd, 0x04);
+ outbyte2 (fd, 0x04);
+
+ return SANE_STATUS_GOOD;
+}
+
+/*
+ * The SCSI-over-parallel scanners need to be handled a bit differently
+ * when opened, as they don't return a valid ASIC ID, so this can't be
+ * used for detecting valid read modes
+ */
+SANE_Status
+sanei_pa4s2_scsi_pp_open (const char *dev, int *fd)
+{
+
+ u_char val;
+ SANE_Status status;
+
+ TEST_DBG_INIT ();
+
+ DBG(4, "sanei_pa4s2_scsi_pp_open: called for device '%s'\n", dev);
+ DBG(5, "sanei_pa4s2_scsi_pp_open: trying to connect to port\n");
+
+ if ((*fd = pa4s2_open (dev, &status)) == -1)
+ {
+
+ DBG (5, "sanei_pa4s2_scsi_pp_open: connection failed\n");
+
+ return status;
+
+ }
+
+ DBG (6, "sanei_pa4s2_scsi_pp_open: connected to device using fd %u\n", *fd);
+
+ DBG (5, "sanei_pa4s2_scsi_pp_open: checking for scanner\n");
+
+ if (sanei_pa4s2_enable (*fd, SANE_TRUE)!=SANE_STATUS_GOOD)
+ {
+ DBG (3, "sanei_pa4s2_scsi_pp_open: error enabling device\n");
+ return SANE_STATUS_IO_ERROR;
+ }
+
+ /*
+ * Instead of checking ASIC ID, check device status
+ */
+ if (sanei_pa4s2_scsi_pp_get_status(*fd, &val)!=SANE_STATUS_GOOD)
+ {
+ DBG (3, "sanei_pa4s2_scsi_pp_open: error getting device status\n");
+ sanei_pa4s2_enable (*fd, SANE_FALSE);
+ return SANE_STATUS_IO_ERROR;
+ }
+ val&=0xf0;
+
+ if ((val==0xf0)||(val&0x40)||(!(val&0x20)))
+ {
+ DBG (3, "sanei_pa4s2_scsi_pp_open: device returned status 0x%02X\n", val);
+ sanei_pa4s2_enable (*fd, SANE_FALSE);
+ return SANE_STATUS_DEVICE_BUSY;
+ }
+
+ if (sanei_pa4s2_enable (*fd, SANE_FALSE)!=SANE_STATUS_GOOD)
+ {
+ DBG (3, "sanei_pa4s2_scsi_pp_open: error disabling device\n");
+ return SANE_STATUS_IO_ERROR;
+ }
+
+ /* FIXME: it would be nice to try to use a better mode here, but how to
+ * know if it's going to work? */
+
+ DBG (4, "sanei_pa4s2_scsi_pp_open: returning SANE_STATUS_GOOD\n");
+
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+sanei_pa4s2_open (const char *dev, int *fd)
+{
+
+ u_char asic, val;
+ SANE_Status status;
+
+ TEST_DBG_INIT ();
+
+ DBG(4, "sanei_pa4s2_open: called for device '%s'\n", dev);
+ DBG(5, "sanei_pa4s2_open: trying to connect to port\n");
+
+ if ((*fd = pa4s2_open (dev, &status)) == -1)
+ {
+
+ DBG (5, "sanei_pa4s2_open: connection failed\n");
+
+ return status;
+
+ }
+
+ DBG (6, "sanei_pa4s2_open: connected to device using fd %u\n", *fd);
+
+ DBG (5, "sanei_pa4s2_open: checking for scanner\n");
+
+ sanei_pa4s2_enable (*fd, SANE_TRUE);
+
+ DBG (6, "sanei_pa4s2_open: reading ASIC id\n");
+
+ sanei_pa4s2_readbegin (*fd, 0);
+
+ sanei_pa4s2_readbyte (*fd, &asic);
+
+ sanei_pa4s2_readend (*fd);
+
+ switch (asic)
+ {
+
+ case PA4S2_ASIC_ID_1013:
+ DBG (3, "sanei_pa4s2_open: detected ASIC id 1013\n");
+ break;
+
+ case PA4S2_ASIC_ID_1015:
+ DBG (3, "sanei_pa4s2_open: detected ASIC id 1015\n");
+ break;
+
+ case PA4S2_ASIC_ID_1505:
+ DBG (3, "sanei_pa4s2_open: detected ASIC id 1505\n");
+ break;
+
+ default:
+ DBG (1, "sanei_pa4s2_open: could not find scanner\n");
+ DBG (3, "sanei_pa4s2_open: reported ASIC id 0x%02x\n",
+ asic);
+
+ sanei_pa4s2_enable (*fd, SANE_FALSE);
+ DBG (5, "sanei_pa4s2_open: closing port\n");
+
+ sanei_pa4s2_close (*fd);
+
+ DBG (5, "sanei_pa4s2_open: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ sanei_pa4s2_enable (*fd, SANE_FALSE);
+
+ DBG (4, "sanei_pa4s2_open: trying better modes\n");
+
+ while (port[*fd].mode <= PA4S2_MODE_EPP)
+ {
+
+ if ((port[*fd].mode == PA4S2_MODE_UNI) &&
+ ((sanei_pa4s2_interface_options & SANEI_PA4S2_OPT_TRY_MODE_UNI) == 0))
+ {
+
+ DBG (3, "sanei_pa4s2_open: skipping mode UNI\n");
+ port[*fd].mode++;
+ continue;
+
+ }
+
+ if ((port[*fd].mode == PA4S2_MODE_EPP) &&
+ ((sanei_pa4s2_interface_options & SANEI_PA4S2_OPT_NO_EPP) != 0))
+ {
+ DBG (3, "sanei_pa4s2_open: skipping mode EPP\n");
+ break;
+ }
+
+
+ DBG (5, "sanei_pa4s2_open: trying mode %u\n", port[*fd].mode);
+
+ sanei_pa4s2_enable (*fd, SANE_TRUE);
+
+ sanei_pa4s2_readbegin (*fd, 0);
+
+ sanei_pa4s2_readbyte (*fd, &val);
+
+ if (val != asic)
+ {
+
+ sanei_pa4s2_readend (*fd);
+ sanei_pa4s2_enable (*fd, SANE_FALSE);
+ DBG (5, "sanei_pa4s2_open: mode failed\n");
+ DBG (6, "sanei_pa4s2_open: returned ASIC-ID 0x%02x\n",
+ (int) val);
+ break;
+
+ }
+
+ sanei_pa4s2_readend (*fd);
+ sanei_pa4s2_enable (*fd, SANE_FALSE);
+
+ DBG (5, "sanei_pa4s2_open: mode works\n");
+
+ port[*fd].mode++;
+
+ }
+
+ port[*fd].mode--;
+
+ if ((port[*fd].mode == PA4S2_MODE_UNI) &&
+ ((sanei_pa4s2_interface_options & SANEI_PA4S2_OPT_TRY_MODE_UNI) == 0))
+ {
+ port[*fd].mode--;
+ }
+
+ DBG (5, "sanei_pa4s2_open: using mode %u\n", port[*fd].mode);
+
+ DBG (4, "sanei_pa4s2_open: returning SANE_STATUS_GOOD\n");
+
+ return SANE_STATUS_GOOD;
+
+}
+
+void
+sanei_pa4s2_close (int fd)
+{
+
+ SANE_Status status;
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_close: fd = %d\n", fd);
+
+#if defined(HAVE_LIBIEEE1284)
+ if ((fd < 0) || (fd >= pplist.portc))
+#else
+ if ((fd < 0) || (fd >= NELEMS (port)))
+#endif
+ {
+
+ DBG (2, "sanei_pa4s2_close: fd %d is invalid\n", fd);
+ DBG (5, "sanei_pa4s2_close: failed\n");
+ return;
+
+ }
+
+ if (port[fd].in_use == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_close: port is not in use\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "sanei_pa4s2_close: port is '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_close: port is 0x%03lx\n", port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_close: failed\n");
+ return;
+
+ }
+
+ DBG (5, "sanei_pa4s2_close: freeing resources\n");
+
+ if (pa4s2_close (fd, &status) == -1)
+ {
+
+ DBG (2, "sanei_pa4s2_close: could not close scanner\n");
+ DBG (5, "sanei_pa4s2_close: failed\n");
+ return;
+ }
+
+ DBG (5, "sanei_pa4s2_close: finished\n");
+
+}
+
+SANE_Status
+sanei_pa4s2_enable (int fd, int enable)
+{
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_enable: called for fd %d with value %d\n",
+ fd, enable);
+
+#if defined(HAVE_LIBIEEE1284)
+ if ((fd < 0) || (fd >= pplist.portc))
+#else
+ if ((fd < 0) || (fd >= NELEMS (port)))
+#endif
+ {
+
+ DBG (2, "sanei_pa4s2_enable: fd %d is invalid\n", fd);
+ DBG (5, "sanei_pa4s2_enable: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].in_use == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_enable: port is not in use\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "sanei_pa4s2_close: port is '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_close: port is 0x%03lx\n", port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_enable: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if ((enable != SANE_TRUE) && (enable != SANE_FALSE))
+ {
+
+ DBG (2, "sanei_pa4s2_enable: invalid value %d\n", enable);
+ DBG (5, "sanei_pa4s2_enable: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if ((unsigned int) enable == port[fd].enabled)
+ {
+
+ DBG (3, "sanei_pa4s2_enable: senseless call...\n");
+ DBG (4, "sanei_pa4s2_enable: aborting\n");
+ DBG (5, "sanei_pa4s2_enable: returning SANE_STATUS_GOOD\n");
+
+ return SANE_STATUS_GOOD;
+
+ }
+
+ if (enable == SANE_TRUE)
+ {
+
+#if defined(HAVE_LIBIEEE1284)
+ DBG (4, "sanei_pa4s2_enable: enable port '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (4, "sanei_pa4s2_enable: enable port 0x%03lx\n", port[fd].base);
+
+ /* io-permissions are not inherited after fork (at least not on
+ linux 2.2, although they seem to be inherited on linux 2.4),
+ so we should make sure we get the permission */
+
+ if (ioperm (port[fd].base, 5, 1))
+ {
+ DBG (1, "sanei_pa4s2_enable: cannot get io privilege for port"
+ " 0x%03lx\n", port[fd].base);
+
+ DBG (5, "sanei_pa4s2_enable:: marking port[%d] as unused\n", fd);
+ port[fd].in_use = SANE_FALSE;
+
+ DBG (5, "sanei_pa4s2_enable:: returning SANE_STATUS_IO_ERROR\n");
+ return SANE_STATUS_IO_ERROR;
+ }
+#endif
+
+ if (pa4s2_enable (fd, port[fd].prelock) != 0)
+ {
+ DBG (1, "sanei_pa4s2_enable: failed to enable port\n");
+ DBG (5, "sanei_pa4s2_enable: returning SANE_STATUS_IO_ERROR\n");
+
+ return SANE_STATUS_IO_ERROR;
+ }
+
+ }
+ else
+ {
+
+#if defined(HAVE_LIBIEEE1284)
+ DBG (4, "sanei_pa4s2_enable: disable port '%s'\n",
+ pplist.portv[fd]->name);
+#else
+ DBG (4, "sanei_pa4s2_enable: disable port 0x%03lx\n", port[fd].base);
+#endif
+
+ pa4s2_disable (fd, port[fd].prelock);
+
+ }
+
+ port[fd].enabled = enable;
+
+ DBG (5, "sanei_pa4s2_enable: returning SANE_STATUS_GOOD\n");
+
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+sanei_pa4s2_readbegin (int fd, u_char reg)
+{
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_readbegin: called for fd %d and register %u\n",
+ fd, (int) reg);
+
+#if defined(HAVE_LIBIEEE1284)
+ if ((fd < 0) || (fd >= pplist.portc))
+#else
+ if ((fd < 0) || (fd >= NELEMS (port)))
+#endif
+ {
+
+ DBG (2, "sanei_pa4s2_readbegin: invalid fd %d\n", fd);
+ DBG (5, "sanei_pa4s2_readbegin: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].in_use == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_readbegin: port is not in use\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "sanei_pa4s2_close: port is '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_close: port is 0x%03lx\n", port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_readbegin: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].enabled == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_readbegin: port is not enabled\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "sanei_pa4s2_close: port is '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_close: port is 0x%03lx\n", port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_readbegin: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ switch (port[fd].mode)
+ {
+
+ case PA4S2_MODE_EPP:
+
+ DBG (5, "sanei_pa4s2_readbegin: EPP readbegin\n");
+ pa4s2_readbegin_epp (fd, reg);
+ break;
+
+ case PA4S2_MODE_UNI:
+
+ DBG (5, "sanei_pa4s2_readbegin: UNI readbegin\n");
+ pa4s2_readbegin_uni (fd, reg);
+ break;
+
+ case PA4S2_MODE_NIB:
+
+ DBG (5, "sanei_pa4s2_readbegin: NIB readbegin\n");
+ pa4s2_readbegin_nib (fd, reg);
+ break;
+
+ default:
+
+ DBG (1, "sanei_pa4s2_readbegin: port info broken\n");
+ DBG (3, "sanei_pa4s2_readbegin: invalid port mode\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "sanei_pa4s2_close: port is '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_close: port is 0x%03lx\n", port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_readbegin: return SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ DBG (5, "sanei_pa4s2_readbegin: returning SANE_STATUS_GOOD\n");
+
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+sanei_pa4s2_readbyte (int fd, u_char * val)
+{
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_readbyte: called with fd %d\n", fd);
+
+ if (val == NULL)
+ {
+
+ DBG (1, "sanei_pa4s2_readbyte: got NULL pointer as result buffer\n");
+ return SANE_STATUS_INVAL;
+
+ }
+
+#if defined(HAVE_LIBIEEE1284)
+ if ((fd < 0) || (fd >= pplist.portc))
+#else
+ if ((fd < 0) || (fd >= NELEMS (port)))
+#endif
+ {
+
+ DBG (2, "sanei_pa4s2_readbyte: invalid fd %d\n", fd);
+ DBG (5, "sanei_pa4s2_readbyte: returning SANE_STATUS_INVAL\n");
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].in_use == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_readbyte: port is not in use\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "sanei_pa4s2_close: port is '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_close: port is 0x%03lx\n", port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_readbyte: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].enabled == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_readbyte: port is not enabled\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "sanei_pa4s2_close: port is '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_close: port is 0x%03lx\n", port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_readbyte: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ DBG (4, "sanei_pa4s2_readbyte: we hope, the backend called\n");
+ DBG (4, "sanei_pa4s2_readbyte: readbegin, so the port is ok...\n");
+
+ DBG (6, "sanei_pa4s2_readbyte: this means, I did not check it - it's\n");
+ DBG (6, "sanei_pa4s2_readbyte: not my fault, if your PC burns down.\n");
+
+ switch (port[fd].mode)
+ {
+
+ case PA4S2_MODE_EPP:
+
+ DBG (5, "sanei_pa4s2_readbyte: read in EPP mode\n");
+ *val = pa4s2_readbyte_epp (fd);
+ break;
+
+
+ case PA4S2_MODE_UNI:
+
+ DBG (5, "sanei_pa4s2_readbyte: read in UNI mode\n");
+ *val = pa4s2_readbyte_uni (fd);
+ break;
+
+
+ case PA4S2_MODE_NIB:
+
+ DBG (5, "sanei_pa4s2_readbyte: read in NIB mode\n");
+ *val = pa4s2_readbyte_nib (fd);
+ break;
+
+ default:
+
+ DBG (1, "sanei_pa4s2_readbyte: port info broken\n");
+ DBG (2, "sanei_pa4s2_readbyte: probably the port wasn't"
+ " correct configured...\n");
+ DBG (3, "sanei_pa4s2_readbyte: invalid port mode\n");
+ DBG (6, "sanei_pa4s2_readbyte: port mode %u\n",
+ port[fd].mode);
+ DBG (6, "sanei_pa4s2_readbyte: I told you!!!\n");
+ DBG (5, "sanei_pa4s2_readbyte: return"
+ " SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+ }
+
+ DBG (5, "sanei_pa4s2_readbyte: read finished\n");
+
+ DBG (6, "sanei_pa4s2_readbyte: got value 0x%02x\n", (int) *val);
+
+ DBG (5, "sanei_pa4s2_readbyte: returning SANE_STATUS_GOOD\n");
+
+ return SANE_STATUS_GOOD;
+
+}
+
+SANE_Status
+sanei_pa4s2_readend (int fd)
+{
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_readend: called for fd %d\n", fd);
+
+#if defined(HAVE_LIBIEEE1284)
+ if ((fd < 0) || (fd >= pplist.portc))
+#else
+ if ((fd < 0) || (fd >= NELEMS (port)))
+#endif
+ {
+
+ DBG (2, "sanei_pa4s2_readend: invalid fd %d\n", fd);
+ DBG (5, "sanei_pa4s2_readend: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].in_use == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_readend: port is not in use\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "sanei_pa4s2_close: port is '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_close: port is 0x%03lx\n", port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_readend: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].enabled == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_readend: port is not enabled\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "sanei_pa4s2_close: port is '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_close: port is 0x%03lx\n", port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_readend: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ DBG (4, "sanei_pa4s2_readend: we hope, the backend called\n");
+ DBG (4, "sanei_pa4s2_readend: readbegin, so the port is ok...\n");
+
+ DBG (6, "sanei_pa4s2_readend: this means, I did not check it - it's\n");
+ DBG (6, "sanei_pa4s2_readend: not my fault, if your PC burns down.\n");
+
+ switch (port[fd].mode)
+ {
+
+ case PA4S2_MODE_EPP:
+
+ DBG (5, "sanei_pa4s2_readend: EPP mode readend\n");
+ pa4s2_readend_epp (fd);
+ break;
+
+
+ case PA4S2_MODE_UNI:
+
+ DBG (5, "sanei_pa4s2_readend: UNI mode readend\n");
+ pa4s2_readend_uni (fd);
+ break;
+
+
+ case PA4S2_MODE_NIB:
+
+ DBG (5, "sanei_pa4s2_readend: NIB mode readend\n");
+ pa4s2_readend_nib (fd);
+ break;
+
+ default:
+
+ DBG (1, "sanei_pa4s2_readend: port info broken\n");
+ DBG (2, "sanei_pa4s2_readend: probably the port wasn't"
+ " correct configured...\n");
+ DBG (3, "sanei_pa4s2_readend: invalid port mode\n");
+ DBG (6, "sanei_pa4s2_readend: port mode %u\n",
+ port[fd].mode);
+ DBG (6, "sanei_pa4s2_readend: I told you!!!\n");
+ DBG (5, "sanei_pa4s2_readend: return"
+ " SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+ }
+
+
+ DBG (5, "sanei_pa4s2_readend: returning SANE_STATUS_GOOD\n");
+
+ return SANE_STATUS_GOOD;
+
+}
+
+SANE_Status
+sanei_pa4s2_writebyte (int fd, u_char reg, u_char val)
+{
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_writebyte: called for fd %d, reg %u and val %u\n",
+ fd, (int) reg, (int) val);
+
+#if defined(HAVE_LIBIEEE1284)
+ if ((fd < 0) || (fd >= pplist.portc))
+#else
+ if ((fd < 0) || (fd >= NELEMS (port)))
+#endif
+ {
+
+ DBG (2, "sanei_pa4s2_writebyte: invalid fd %d\n", fd);
+ DBG (5, "sanei_pa4s2_writebyte: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].in_use == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_writebyte: port is not in use\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "sanei_pa4s2_close: port is '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_close: port is 0x%03lx\n", port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_writebyte: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ if (port[fd].enabled == SANE_FALSE)
+ {
+
+ DBG (2, "sanei_pa4s2_writebyte: port is not enabled\n");
+#if defined(HAVE_LIBIEEE1284)
+ DBG (6, "sanei_pa4s2_close: port is '%s'\n", pplist.portv[fd]->name);
+#else
+ DBG (6, "sanei_pa4s2_close: port is 0x%03lx\n", port[fd].base);
+#endif
+ DBG (5, "sanei_pa4s2_readbegin: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ switch (port[fd].mode)
+ {
+
+ case PA4S2_MODE_EPP:
+ case PA4S2_MODE_UNI:
+ case PA4S2_MODE_NIB:
+
+ DBG (5, "sanei_pa4s2_writebyte: NIB/UNI/EPP write\n");
+ pa4s2_writebyte_any (fd, reg, val);
+ break;
+
+ default:
+
+ DBG (1, "sanei_pa4s2_writebyte: port info broken\n");
+ DBG (3, "sanei_pa4s2_writebyte: invalid port mode\n");
+ DBG (6, "sanei_pa4s2_writebyte: port mode %u\n",
+ port[fd].mode);
+ DBG (5, "sanei_pa4s2_writebyte: return"
+ " SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+ }
+
+ DBG (5, "sanei_pa4s2_writebyte: returning SANE_STATUS_GOOD\n");
+
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+sanei_pa4s2_options (u_int * options, int set)
+{
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_options: called with options %u and set = %d\n",
+ *options, set);
+
+ if ((set != SANE_TRUE) && (set != SANE_FALSE))
+ DBG (2, "sanei_pa4s2_options: value of set is invalid\n");
+
+ if ((set == SANE_TRUE) && (*options > 7))
+ DBG (2, "sanei_pa4s2_options: value of *options is invalid\n");
+
+ if (set == SANE_TRUE)
+ {
+
+ DBG (5, "sanei_pa4s2_options: setting options to %u\n", *options);
+
+ sanei_pa4s2_interface_options = *options;
+
+ }
+ else
+ {
+
+ DBG (5, "sanei_pa4s2_options: options are set to %u\n",
+ sanei_pa4s2_interface_options);
+
+ *options = sanei_pa4s2_interface_options;
+
+ }
+
+ DBG (5, "sanei_pa4s2_options: returning SANE_STATUS_GOOD\n");
+
+ return SANE_STATUS_GOOD;
+
+}
+
+#else /* !HAVE_IOPERM */
+
+
+SANE_Status
+sanei_pa4s2_open (const char *dev, int *fd)
+{
+
+ TEST_DBG_INIT ();
+
+ if (fd)
+ *fd = -1;
+
+ DBG (4, "sanei_pa4s2_open: called for device `%s`\n", dev);
+ DBG (3, "sanei_pa4s2_open: A4S2 support not compiled\n");
+ DBG (6, "sanei_pa4s2_open: basically, this backend does only compile\n");
+ DBG (6, "sanei_pa4s2_open: on x86 architectures. Furthermore it\n");
+ DBG (6, "sanei_pa4s2_open: needs ioperm() and inb()/outb() calls.\n");
+ DBG (6, "sanei_pa4s2_open: alternativly it makes use of libieee1284\n");
+ DBG (6, "sanei_pa4s2_open: (which isn't present either)\n");
+ DBG (5, "sanei_pa4s2_open: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+}
+
+void
+sanei_pa4s2_close (int fd)
+{
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_close: called for fd %d\n", fd);
+ DBG (2, "sanei_pa4s2_close: fd %d is invalid\n", fd);
+ DBG (3, "sanei_pa4s2_close: A4S2 support not compiled\n");
+ DBG (6, "sanei_pa4s2_close: so I wonder, why this function is called"
+ " anyway.\n");
+ DBG (6, "sanei_pa4s2_close: maybe this is a bug in the backend.\n");
+ DBG (5, "sanei_pa4s2_close: returning\n");
+
+ return;
+}
+
+SANE_Status
+sanei_pa4s2_enable (int fd, int enable)
+{
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_enable: called for fd %d with value=%d\n",
+ fd, enable);
+ DBG (2, "sanei_pa4s2_enable: fd %d is invalid\n", fd);
+
+ if ((enable != SANE_TRUE) && (enable != SANE_FALSE))
+ DBG (2, "sanei_pa4s2_enable: value %d is invalid\n", enable);
+
+ DBG (3, "sanei_pa4s2_enable: A4S2 support not compiled\n");
+ DBG (6, "sanei_pa4s2_enable: oops, I think there's someone going to\n");
+ DBG (6, "sanei_pa4s2_enable: produce a lot of garbage...\n");
+ DBG (5, "sanei_pa4s2_enable: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+}
+
+SANE_Status
+sanei_pa4s2_readbegin (int fd, u_char reg)
+{
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_readbegin: called for fd %d and register %d\n",
+ fd, (int) reg);
+ DBG (2, "sanei_pa4s2_readbegin: fd %d is invalid\n", fd);
+
+ DBG (3, "sanei_pa4s2_readbegin: A4S2 support not compiled\n");
+ DBG (6, "sanei_pa4s2_readbegin: don't look - this is going to be\n");
+ DBG (6, "sanei_pa4s2_readbegin: worse then you'd expect...\n");
+ DBG (5, "sanei_pa4s2_readbegin: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+}
+
+SANE_Status
+sanei_pa4s2_readbyte (int fd, u_char * val)
+{
+
+ TEST_DBG_INIT ();
+
+ if (val)
+ *val = 0;
+
+ DBG (4, "sanei_pa4s2_readbyte: called for fd %d\n", fd);
+ DBG (2, "sanei_pa4s2_readbyte: fd %d is invalid\n", fd);
+ DBG (3, "sanei_pa4s2_readbyte: A4S2 support not compiled\n");
+ DBG (6, "sanei_pa4s2_readbyte: shit happens\n");
+ DBG (5, "sanei_pa4s2_readbyte: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+}
+
+SANE_Status
+sanei_pa4s2_readend (int fd)
+{
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_readend: called for fd %d\n", fd);
+ DBG (2, "sanei_pa4s2_readend: fd %d is invalid\n", fd);
+ DBG (3, "sanei_pa4s2_readend: A4S2 support not compiled\n");
+ DBG (6, "sanei_pa4s2_readend: it's too late anyway\n");
+ DBG (5, "sanei_pa4s2_readend: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+}
+
+SANE_Status
+sanei_pa4s2_writebyte (int fd, u_char reg, u_char val)
+{
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_writebyte: called for fd %d and register %d, "
+ "value = %u\n", fd, (int) reg, (int) val);
+ DBG (2, "sanei_pa4s2_writebyte: fd %d is invalid\n", fd);
+ DBG (3, "sanei_pa4s2_writebyte: A4S2 support not compiled\n");
+ DBG (6, "sanei_pa4s2_writebyte: whatever backend you're using, tell\n");
+ DBG (6, "sanei_pa4s2_writebyte: the maintainer his code has bugs...\n");
+ DBG (5, "sanei_pa4s2_writebyte: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+}
+
+SANE_Status
+sanei_pa4s2_options (u_int * options, int set)
+{
+
+ TEST_DBG_INIT ();
+
+ DBG (4, "sanei_pa4s2_options: called with options %u and set = %d\n",
+ *options, set);
+
+ if ((set != SANE_TRUE) && (set != SANE_FALSE))
+ DBG (2, "sanei_pa4s2_options: value of set is invalid\n");
+
+ if ((set == SANE_TRUE) && (*options > 3))
+ DBG (2, "sanei_pa4s2_options: value of *options is invalid\n");
+
+ DBG (3, "sanei_pa4s2_options: A4S2 support not compiled\n");
+ DBG (5, "sanei_pa4s2_options: returning SANE_STATUS_INVAL\n");
+
+ return SANE_STATUS_INVAL;
+
+}
+
+const char **
+sanei_pa4s2_devices()
+{
+ TEST_DBG_INIT ();
+ DBG (4, "sanei_pa4s2_devices: invoked\n");
+
+ DBG (3, "sanei_pa4s2_devices: A4S2 support not compiled\n");
+ DBG (5, "sanei_pa4s2_devices: returning empty list\n");
+
+ return calloc(1, sizeof(char *));
+}
+
+SANE_Status
+sanei_pa4s2_scsi_pp_get_status(int fd, u_char *status)
+{
+ TEST_DBG_INIT ();
+ DBG (4, "sanei_pa4s2_scsi_pp_get_status: fd=%d, status=%p\n",
+ fd, (void *) status);
+ DBG (3, "sanei_pa4s2_scsi_pp_get_status: A4S2 support not compiled\n");
+ return SANE_STATUS_UNSUPPORTED;
+}
+
+SANE_Status
+sanei_pa4s2_scsi_pp_reg_select (int fd, int reg)
+{
+ TEST_DBG_INIT ();
+ DBG (4, "sanei_pa4s2_scsi_pp_reg_select: fd=%d, reg=%d\n",
+ fd, reg);
+ DBG (3, "sanei_pa4s2_devices: A4S2 support not compiled\n");
+ return SANE_STATUS_UNSUPPORTED;
+}
+
+SANE_Status
+sanei_pa4s2_scsi_pp_open (const char *dev, int *fd)
+{
+ TEST_DBG_INIT ();
+ DBG (4, "sanei_pa4s2_scsi_pp_open: dev=%s, fd=%p\n",
+ dev, (void *) fd);
+ DBG (3, "sanei_pa4s2_scsi_pp_open: A4S2 support not compiled\n");
+ return SANE_STATUS_UNSUPPORTED;
+}
+
+#endif /* !HAVE_IOPERM */