/* sane - Scanner Access Now Easy. * Copyright (C) 2003-2005 Gerhard Jaeger * based on work done by Jochen Eisinger * also parts from libieee1284 by Tim Waugh * 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 accessing the parallelport */ /* 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_PP */ #include "../include/sane/config.h" #define BACKEND_NAME sanei_pp #define _TEST_LOOPS 1000 #define _MAX_PORTS 20 #ifndef _VAR_NOT_USED # define _VAR_NOT_USED(x) ((x)=(x)) #endif /* uncomment this to have some parameter checks on in/out functions, * note: that this will slow down the calls */ #if 0 # define _PARANOIA #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_LIMITS_H # include #else # ifndef ULONG_MAX # define ULONG_MAX 4294967295UL # endif #endif #if defined (ENABLE_PARPORT_DIRECTIO) # undef HAVE_LIBIEEE1284 # if defined(HAVE_SYS_IO_H) # if defined (__ICC) && __ICC >= 700 # define __GNUC__ 2 # endif # include # ifndef SANE_HAVE_SYS_IO_H_WITH_INB_OUTB # define IO_SUPPORT_MISSING # endif # if defined (__ICC) && __ICC >= 700 # undef __GNUC__ # elif defined(__ICC) && defined(HAVE_ASM_IO_H) # include # endif # elif defined(HAVE_ASM_IO_H) # include # elif defined(HAVE_SYS_HW_H) # include # 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; } # endif #elif defined(HAVE_LIBIEEE1284) # include #else # if defined(__GNUC__) # warning "No I/O support for this architecture!" # endif # define IO_SUPPORT_MISSING #endif #include "../include/sane/sane.h" #include "../include/sane/sanei.h" #include "../include/sane/sanei_debug.h" #include "../include/sane/sanei_pp.h" #if defined(STDC_HEADERS) # include # include # include #endif #if defined(HAVE_STRING_H) # include #elif defined(HAVE_STRINGS_H) # include #endif #if defined(HAVE_SYS_TYPES_H) # include #endif /** our global init flag... */ static int first_time = SANE_TRUE; static unsigned long pp_thresh = 0; #if (defined (HAVE_IOPERM) || defined (HAVE_LIBIEEE1284)) && !defined (IO_SUPPORT_MISSING) typedef struct { #ifndef HAVE_LIBIEEE1284 const char name[6]; u_long base; /**< i/o base address */ u_char ctrl; /**< for restoring CTRL register */ u_char ecp_ctrl; /**< for restoring ECP-CTRL register */ #endif u_int in_use; /**< port in use? */ u_int claimed; /**< port claimed? */ int caps; /**< port capabilities */ } PortRec, *Port; #if defined (HAVE_LIBIEEE1284) static struct parport_list pplist; static PortRec port[_MAX_PORTS]; #else /** redefine the CAPability flags */ enum ieee1284_capabilities { CAP1284_RAW = (1<<0), CAP1284_NIBBLE = (1<<1), /* SPP mode */ CAP1284_BYTE = (1<<2), /* PS/2 bidirectional */ CAP1284_COMPAT = (1<<3), CAP1284_BECP = (1<<4), CAP1284_ECP = (1<<5), /* ECP */ CAP1284_ECPRLE = (1<<6), /* ECP with RLE support */ CAP1284_ECPSWE = (1<<7), CAP1284_EPP = (1<<8), /* EPP hardware support */ CAP1284_EPPSL = (1<<9), /* EPP 1.7 */ CAP1284_EPPSWE = (1<<10) /* EPP software support */ }; static PortRec port[] = { { "0x378", 0x378, 0, 0, SANE_FALSE, SANE_FALSE, 0 }, { "0x278", 0x278, 0, 0, SANE_FALSE, SANE_FALSE, 0 }, { "0x3BC", 0x3BC, 0, 0, SANE_FALSE, SANE_FALSE, 0 } }; #endif /** depending on the interface we use, define the port macros */ #if defined(HAVE_LIBIEEE1284) #define inb_data(fd) ieee1284_read_data(pplist.portv[fd]); #define inb_stat(fd) (ieee1284_read_status(pplist.portv[fd]) ^ S1284_INVERTED) #define inb_ctrl(fd) (ieee1284_read_control(pplist.portv[fd]) ^ C1284_INVERTED) static inline u_char inb_eppdata(int fd) { u_char val; ieee1284_epp_read_data(pplist.portv[fd], 0, (char *)&val, 1); return val; } static inline void outb_eppdata(int fd, u_char val) { ieee1284_epp_write_data(pplist.portv[fd], 0, (const char *)&val, 1); } #define outb_data(fd,val) ieee1284_write_data(pplist.portv[fd], val) #define outb_ctrl(fd,val) ieee1284_write_control(pplist.portv[fd], \ (val) ^ C1284_INVERTED) static inline void outb_addr(int fd, u_char val) { ieee1284_epp_write_addr (pplist.portv[fd], 0, (char *)&val, 1); } #else #define inb_data(fd) inb(port[fd].base) #define inb_stat(fd) inb(port[fd].base + 1) #define inb_ctrl(fd) inb(port[fd].base + 2) #define inb_eppdata(fd) inb(port[fd].base + 4) #define outb_data(fd,val) outb(val, port[fd].base) #define outb_stat(fd,val) outb(val, port[fd].base + 1) #define outb_ctrl(fd,val) outb(val, port[fd].base + 2) #define outb_addr(fd,val) outb(val, port[fd].base + 3) #define outb_eppdata(fd,val) outb(val, port[fd].base + 4) #ifdef HAVE_IOPL # define _SET_IOPL() iopl(3) # define inbyte400(fd) inb(port[fd].base + 0x400) # define inbyte402(fd) inb(port[fd].base + 0x402) # define outbyte400(fd,val) outb(val, port[fd].base + 0x400) # define outbyte402(fd,val) outb(val, port[fd].base + 0x402) #else # define _SET_IOPL() # define inbyte400(fd) # define inbyte402(fd,val) # define outbyte400(fd,val) # define outbyte402(fd,val) #endif #endif /* should also be in unistd.h */ extern int setuid (uid_t); #if defined (HAVE_LIBIEEE1284) static const char *pp_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 /** show the caps */ static int pp_showcaps( int caps ) { int mode = 0; char ct[1024]; ct[0] = '\0'; if( caps & CAP1284_NIBBLE ) { strcat( ct, "SPP " ); mode |= SANEI_PP_MODE_SPP; } if( caps & CAP1284_BYTE ) { strcat( ct, "PS/2 " ); mode |= SANEI_PP_MODE_BIDI; } if( caps & CAP1284_EPP ) { strcat( ct, "EPP " ); mode |= SANEI_PP_MODE_EPP; } if( caps & CAP1284_EPPSWE ) { strcat( ct, "EPPSWE " ); mode |= SANEI_PP_MODE_EPP; } if( caps & CAP1284_ECP ) { strcat( ct, "ECP " ); mode |= SANEI_PP_MODE_ECP; } if( caps & CAP1284_ECPRLE ) { strcat( ct, "ECPRLE " ); mode |= SANEI_PP_MODE_ECP; } DBG( 4, "Supported Modes: %s\n", ct ); return mode; } #ifndef HAVE_LIBIEEE1284 /** probe the parallel port */ static int pp_probe( int fd ) { #ifdef HAVE_IOPL SANE_Byte c; int i, j; #endif SANE_Byte a, b; int retv = 0; DBG( 4, "pp_probe: port 0x%04lx\n", port[fd].base ); /* SPP check */ outbyte402( fd, 0x0c ); outb_ctrl ( fd, 0x0c ); outb_data ( fd, 0x55 ); a = inb_data( fd ); if( a != 0x55 ) { DBG( 4, "pp_probe: nothing supported :-(\n" ); return retv; } DBG( 4, "pp_probe: SPP port present\n" ); retv += CAP1284_NIBBLE; /* check for ECP */ #ifdef HAVE_IOPL /* clear at most 1k of data from FIFO */ for( i = 1024; i > 0; i-- ) { a = inbyte402( fd ); if ((a & 0x03) == 0x03) goto no_ecp; if (a & 0x01) break; inbyte400( fd ); /* Remove byte from FIFO */ } if (i <= 0) goto no_ecp; b = a ^ 3; outbyte402( fd, b ); c = inbyte402( fd ); if (a == c) { outbyte402( fd, 0xc0 ); /* FIFO test */ j = 0; while (!(inbyte402( fd ) & 0x01) && (j < 1024)) { inbyte402( fd ); j++; } if (j >= 1024) goto no_ecp; i = 0; j = 0; while (!(inbyte402( fd ) & 0x02) && (j < 1024)) { outbyte400( fd, 0x00 ); i++; j++; } if (j >= 1024) goto no_ecp; j = 0; while (!(inbyte402( fd ) & 0x01) && (j < 1024)) { inbyte400( fd ); j++; } if (j >= 1024) goto no_ecp; DBG( 4, "pp_probe: ECP with a %i byte FIFO present\n", i ); retv += CAP1284_ECP; } no_ecp: #endif /* check for PS/2 compatible port */ if( retv & CAP1284_ECP ) { outbyte402( fd, 0x20 ); } outb_data( fd, 0x55 ); outb_ctrl( fd, 0x0c ); a = inb_data( fd ); outb_data( fd, 0x55 ); outb_ctrl( fd, 0x2c ); b = inb_data( fd ); if( a != b ) { DBG( 4, "pp_probe: PS/2 bidirectional port present\n"); retv += CAP1284_BYTE; } /* check for EPP support */ if( port[fd].base & 0x007 ) { DBG( 4, "pp_probe: EPP not supported at this address\n" ); return retv; } #ifdef HAVE_IOPL if( retv & CAP1284_ECP ) { for( i = 0x00; i < 0x80; i += 0x20 ) { outbyte402( fd, i ); a = inb_stat( fd ); outb_stat( fd, a ); outb_stat( fd, (a & 0xfe)); a = inb_stat( fd ); if (!(a & 0x01)) { DBG( 2, "pp_probe: " "Failed Intel bug check. (Phony EPP in ECP)\n" ); return retv; } } DBG( 4, "pp_probe: Passed Intel bug check.\n" ); outbyte402( fd, 0x80 ); } #endif a = inb_stat( fd ); outb_stat( fd, a ); outb_stat( fd, (a & 0xfe)); a = inb_stat( fd ); if (a & 0x01) { outbyte402( fd, 0x0c ); outb_ctrl ( fd, 0x0c ); return retv; } outb_ctrl( fd, 0x04 ); inb_eppdata ( fd ); a = inb_stat( fd ); outb_stat( fd, a ); outb_stat( fd, (a & 0xfe)); if( a & 0x01 ) { DBG( 4, "pp_probe: EPP 1.9 with hardware direction protocol\n"); retv += CAP1284_EPP; } else { /* The EPP timeout bit was not set, this could either be: * EPP 1.7 * EPP 1.9 with software direction */ outb_ctrl( fd, 0x24 ); inb_eppdata ( fd ); a = inb_stat( fd ); outb_stat( fd, a ); outb_stat( fd, (a & 0xfe)); if( a & 0x01 ) { DBG( 4, "pp_probe: EPP 1.9 with software direction protocol\n" ); retv += CAP1284_EPPSWE; } else { DBG( 4, "pp_probe: EPP 1.7\n" ); retv += CAP1284_EPPSL; } } outbyte402( fd, 0x0c ); outb_ctrl ( fd, 0x0c ); return retv; } /** */ static int pp_set_scpmode( int fd ) { SANE_Byte tmp; DBG( 4, "pp_set_scpmode\n" ); #ifdef HAVE_IOPL tmp = inbyte402( fd ); tmp &= 0x1f; outbyte402( fd, tmp ); #endif tmp = inb_ctrl( fd ); tmp &= 0x0f; outb_ctrl ( fd, tmp ); return SANE_STATUS_GOOD; } static int pp_set_bidimode( int fd ) { SANE_Byte tmp; DBG( 4, "pp_set_bidimode\n" ); #ifdef HAVE_IOPL tmp = inbyte402( fd ); tmp = (tmp & 0x1f) | 0x20; outbyte402( fd, tmp ); #endif tmp = inb_ctrl( fd ); tmp = (tmp & 0x0f) | 0x20; outb_ctrl ( fd, tmp ); return SANE_STATUS_GOOD; } static int pp_set_eppmode( int fd ) { SANE_Byte tmp; DBG( 4, "pp_set_eppmode\n" ); #ifdef HAVE_IOPL tmp = inbyte402( fd ); tmp = (tmp & 0x1f) | 0x80; outbyte402( fd, tmp ); #endif tmp = inb_ctrl( fd ); tmp = (tmp & 0xf0) | 0x40; outb_ctrl ( fd, tmp ); return SANE_STATUS_GOOD; } static int pp_set_ecpmode( int fd ) { #ifdef HAVE_IOPL SANE_Byte tmp; #endif DBG( 4, "pp_set_ecpmode\n" ); #ifdef HAVE_IOPL tmp = inbyte402( fd ); tmp = (tmp & 0x1f) | 0x60; outbyte402( fd, tmp ); return SANE_STATUS_GOOD; #endif return SANE_STATUS_UNSUPPORTED; } /** set the parallel port mode */ static int pp_setmode( int fd, int mode ) { int ret; if( 0 == (mode & port[fd].caps)) { DBG( 2, "pp_setmode: mode not supported %d\n", mode ); return SANE_STATUS_UNSUPPORTED; } switch( mode ) { case SANEI_PP_MODE_SPP: ret = pp_set_scpmode( fd ); break; case SANEI_PP_MODE_BIDI: ret = pp_set_bidimode( fd ); break; case SANEI_PP_MODE_EPP: ret = pp_set_eppmode( fd ); break; case SANEI_PP_MODE_ECP: ret = pp_set_ecpmode( fd ); break; default: DBG( 2, "pp_setmode: invalid mode %d\n", mode ); return SANE_STATUS_INVAL; } return ret; } #endif static unsigned long pp_time_diff( struct timeval *start, struct timeval *end ) { double s, e, r; s = (double)start->tv_sec * 1000000.0 + (double)start->tv_usec; e = (double)end->tv_sec * 1000000.0 + (double)end->tv_usec; if( e > s ) r = (e - s); else r = (s - e); if( r <= (double)ULONG_MAX ) return (unsigned long)r; return 0; } /** */ static unsigned long pp_calculate_thresh( void ) { unsigned long i, r, ret; struct timeval start, end, deadline; gettimeofday( &start, NULL); for( i = _TEST_LOOPS; i; i-- ) { gettimeofday( &deadline, NULL ); deadline.tv_usec += 10; deadline.tv_sec += deadline.tv_usec / 1000000; deadline.tv_usec %= 1000000; } gettimeofday( &end, NULL); r = pp_time_diff( &start, &end ); ret = r/_TEST_LOOPS; return ret; } /** */ static void pp_calibrate_delay( void ) { unsigned long r, i; struct timeval start, end; for( i = 0; i < 5; i++ ) { pp_thresh = pp_calculate_thresh(); gettimeofday( &start, NULL); for( i = _TEST_LOOPS; i; i-- ) { sanei_pp_udelay( 1 ); } gettimeofday( &end, NULL); r = pp_time_diff( &start, &end ); DBG( 4, "pp_calibrate_delay: Delay expected: " "%u, real %lu, pp_thresh=%lu\n", _TEST_LOOPS, r, pp_thresh ); if( r >= _TEST_LOOPS ) { return; } } DBG( 4, "pp_calibrate_delay: pp_thresh set to 0\n" ); pp_thresh = 0; } static SANE_Status pp_init( void ) { #if defined (HAVE_LIBIEEE1284) int result, i; #endif if( first_time == SANE_FALSE ) { DBG( 5, "pp_init: already initalized\n" ); return SANE_STATUS_GOOD; } DBG( 5, "pp_init: called for the first time\n"); first_time = SANE_FALSE; #if defined (HAVE_LIBIEEE1284) DBG( 4, "pp_init: initializing libieee1284\n"); result = ieee1284_find_ports( &pplist, 0 ); if (result) { DBG (1, "pp_init: initializing IEEE 1284 failed (%s)\n", pp_libieee1284_errorstr( result )); first_time = SANE_TRUE; return SANE_STATUS_INVAL; } DBG( 3, "pp_init: %d ports reported by IEEE 1284 library\n", pplist.portc); for( i = 0; i < pplist.portc; i++ ) DBG( 6, "pp_init: port %d is `%s`\n", i, pplist.portv[i]->name); /* we support only up to _MAX_PORTS... */ if( pplist.portc > _MAX_PORTS ) { DBG (1, "pp_init: Lib IEEE 1284 reports too much ports: %d\n", pplist.portc ); ieee1284_free_ports( &pplist ); first_time = SANE_TRUE; return SANE_STATUS_UNSUPPORTED; } memset( port, 0, sizeof(port)); #else DBG( 4, "pp_init: trying to setuid root\n"); if( 0 > setuid( 0 )) { DBG( 1, "pp_init: setuid failed: errno = %d\n", errno ); DBG( 5, "pp_init: returning SANE_STATUS_INVAL\n" ); first_time = SANE_TRUE; return SANE_STATUS_INVAL; } DBG( 3, "pp_init: the application is now root\n" ); #endif DBG( 5, "pp_init: initialized successfully\n" ); return SANE_STATUS_GOOD; } static int pp_open( const char *dev, SANE_Status * status ) { int i; #if !defined (HAVE_LIBIEEE1284) u_long base; #else int result; #endif DBG( 4, "pp_open: trying to attach dev `%s`\n", dev ); #if !defined (HAVE_LIBIEEE1284) { char *end; DBG( 5, "pp_open: reading port number\n" ); base = strtol( dev, &end, 0 ); if ((end == dev) || (*end != '\0')) { DBG( 1, "pp_open: `%s` is not a valid port number\n", dev); DBG( 6, "pp_open: the part I did not understand was ...`%s`\n", end); *status = SANE_STATUS_INVAL; return -1; } } DBG( 6, "pp_open: read port number 0x%03lx\n", base ); if( base == 0 ) { DBG( 1, "pp_open: 0x%03lx is not a valid base address\n", base ); *status = SANE_STATUS_INVAL; return -1; } #endif DBG( 5, "pp_open: looking up port in list\n" ); #if defined (HAVE_LIBIEEE1284) for( i = 0; i < pplist.portc; i++ ) { DBG( 5, "pp_open: checking >%s<\n", pplist.portv[i]->name ); if( !strcmp(pplist.portv[i]->name, dev)) break; } if( pplist.portc <= i ) { DBG( 1, "pp_open: `%s` is not a valid device name\n", dev ); *status = SANE_STATUS_INVAL; return -1; } #else for( i = 0; i < NELEMS(port); i++ ) { if( port[i].base == base ) break; } if (NELEMS (port) <= i) { DBG( 1, "pp_open: 0x%03lx is not a valid base address\n", base ); *status = SANE_STATUS_INVAL; return -1; } #endif DBG( 6, "pp_open: port is in list at port[%d]\n", i); if( port[i].in_use == SANE_TRUE) { #if defined (HAVE_LIBIEEE1284) DBG( 1, "pp_open: device `%s` is already in use\n", dev ); #else DBG( 1, "pp_open: port 0x%03lx is already in use\n", base ); #endif *status = SANE_STATUS_DEVICE_BUSY; return -1; } port[i].in_use = SANE_TRUE; port[i].claimed = SANE_FALSE; #if defined (HAVE_LIBIEEE1284) DBG( 5, "pp_open: opening device\n" ); result = ieee1284_open( pplist.portv[i], 0, &port[i].caps ); if (result) { DBG( 1, "pp_open: could not open device `%s` (%s)\n", dev, pp_libieee1284_errorstr (result)); port[i].in_use = SANE_FALSE; *status = SANE_STATUS_ACCESS_DENIED; return -1; } #else DBG( 5, "pp_open: getting io permissions\n" ); /* TODO: insert FreeBSD compatible code here */ if( ioperm( port[i].base, 5, 1 )) { DBG( 1, "pp_open: cannot get io privilege for port 0x%03lx\n", port[i].base); port[i].in_use = SANE_FALSE; *status = SANE_STATUS_IO_ERROR; return -1; } /* save the CTRL register settings */ #ifdef HAVE_IOPL _SET_IOPL(); port[i].ecp_ctrl = inbyte402(i); port[i].ctrl = inb_ctrl(i); #endif /* check the capabilities of this port */ port[i].caps = pp_probe( i ); #endif port[i].caps = pp_showcaps( port[i].caps ); DBG( 3, "pp_open: device `%s` opened...\n", dev ); *status = SANE_STATUS_GOOD; return i; } static int pp_close( int fd, SANE_Status *status ) { #if defined(HAVE_LIBIEEE1284) int result; #endif DBG( 4, "pp_close: fd=%d\n", fd ); #if defined(HAVE_LIBIEEE1284) DBG( 6, "pp_close: this is port '%s'\n", pplist.portv[fd]->name ); #else DBG( 6, "pp_close: this is port 0x%03lx\n", port[fd].base ); DBG( 6, "pp_close: restoring the CTRL registers\n" ); outb_ctrl( fd, port[fd].ctrl ); #ifdef HAVE_IOPL outbyte402( fd, port[fd].ecp_ctrl ); #endif #endif if( port[fd].claimed == SANE_TRUE ) { sanei_pp_release( fd ); } DBG( 5, "pp_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, "pp_close: can't free port '%s' (%s)\n", pplist.portv[fd]->name, pp_libieee1284_errorstr(result)); #else DBG( 1, "pp_close: can't free port 0x%03lx\n", port[fd].base ); #endif *status = SANE_STATUS_IO_ERROR; return -1; } DBG( 5, "pp_close: marking port as unused\n" ); port[fd].in_use = SANE_FALSE; *status = SANE_STATUS_GOOD; return 0; } /** exported functions **/ SANE_Status sanei_pp_init( void ) { SANE_Status result; DBG_INIT(); result = pp_init(); if( result != SANE_STATUS_GOOD ) { return result; } pp_calibrate_delay(); return SANE_STATUS_GOOD; } SANE_Status sanei_pp_open( const char *dev, int *fd ) { SANE_Status status; DBG( 4, "sanei_pp_open: called for device '%s'\n", dev); *fd = pp_open( dev, &status ); if( *fd == -1 ) { DBG( 5, "sanei_pp_open: connection failed\n" ); return status; } DBG( 6, "sanei_pp_open: connected to device using fd %u\n", *fd ); return SANE_STATUS_GOOD; } void sanei_pp_close( int fd ) { SANE_Status status; DBG( 4, "sanei_pp_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_pp_close: fd %d is invalid\n", fd ); return; } if( port[fd].in_use == SANE_FALSE ) { DBG( 2, "sanei_pp_close: port is not in use\n" ); #if defined(HAVE_LIBIEEE1284) DBG( 6, "sanei_pp_close: port is '%s'\n", pplist.portv[fd]->name ); #else DBG( 6, "sanei_pp_close: port is 0x%03lx\n", port[fd].base ); #endif return; } DBG( 5, "sanei_pp_close: freeing resources\n" ); if( pp_close (fd, &status) == -1 ) { DBG( 5, "sanei_pp_close: failed\n" ); return; } DBG( 5, "sanei_pp_close: finished\n" ); } SANE_Status sanei_pp_claim( int fd ) { #if defined (HAVE_LIBIEEE1284) int result; #endif DBG( 4, "sanei_pp_claim: fd = %d\n", fd ); #if defined (HAVE_LIBIEEE1284) if((fd < 0) || (fd >= pplist.portc)) { DBG( 2, "sanei_pp_claim: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } result = ieee1284_claim (pplist.portv[fd]); if (result) { DBG (1, "sanei_pp_claim: failed (%s)\n", pp_libieee1284_errorstr(result)); return -1; } #endif port[fd].claimed = SANE_TRUE; return SANE_STATUS_GOOD; } SANE_Status sanei_pp_release( int fd ) { DBG( 4, "sanei_pp_release: fd = %d\n", fd ); #if defined(HAVE_LIBIEEE1284) if((fd < 0) || (fd >= pplist.portc)) { DBG( 2, "sanei_pp_release: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } ieee1284_release( pplist.portv[fd] ); #endif port[fd].claimed = SANE_FALSE; return SANE_STATUS_GOOD; } SANE_Status sanei_pp_outb_data( int fd, SANE_Byte val ) { #ifdef _PARANOIA DBG( 4, "sanei_pp_outb_data: 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_pp_outb_data: invalid fd %d\n", fd ); return SANE_STATUS_INVAL; } #endif outb_data( fd, val ); return SANE_STATUS_GOOD; } SANE_Status sanei_pp_outb_ctrl( int fd, SANE_Byte val ) { #ifdef _PARANOIA DBG( 4, "sanei_pp_outb_ctrl: 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_pp_outb_ctrl: invalid fd %d\n", fd ); return SANE_STATUS_INVAL; } #endif outb_ctrl( fd, val ); return SANE_STATUS_GOOD; } SANE_Status sanei_pp_outb_addr( int fd, SANE_Byte val ) { #ifdef _PARANOIA DBG( 4, "sanei_pp_outb_addr: 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_pp_outb_addr: invalid fd %d\n", fd ); return SANE_STATUS_INVAL; } #endif outb_addr( fd, val ); return SANE_STATUS_GOOD; } SANE_Status sanei_pp_outb_epp( int fd, SANE_Byte val ) { #ifdef _PARANOIA DBG( 4, "sanei_pp_outb_epp: 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_pp_outb_epp: invalid fd %d\n", fd ); return SANE_STATUS_INVAL; } #endif outb_eppdata( fd, val ); return SANE_STATUS_GOOD; } SANE_Byte sanei_pp_inb_data( int fd ) { #ifdef _PARANOIA DBG( 4, "sanei_pp_inb_data: 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_pp_inb_data: invalid fd %d\n", fd ); return SANE_STATUS_INVAL; } #endif return inb_data( fd ); } SANE_Byte sanei_pp_inb_stat( int fd ) { #ifdef _PARANOIA DBG( 4, "sanei_pp_inb_stat: 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_pp_outb_stat: invalid fd %d\n", fd ); return SANE_STATUS_INVAL; } #endif return inb_stat( fd ); } SANE_Byte sanei_pp_inb_ctrl( int fd ) { #ifdef _PARANOIA DBG( 4, "sanei_pp_inb_ctrl: 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_pp_inb_ctrl: invalid fd %d\n", fd ); return SANE_STATUS_INVAL; } #endif return inb_ctrl( fd ); } SANE_Byte sanei_pp_inb_epp( int fd ) { #ifdef _PARANOIA DBG( 4, "sanei_pp_inb_epp: 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_pp_inb_epp: invalid fd %d\n", fd ); return SANE_STATUS_INVAL; } #endif return inb_eppdata( fd ); } SANE_Status sanei_pp_getmodes( int fd, int *mode ) { #if defined(HAVE_LIBIEEE1284) if ((fd < 0) || (fd >= pplist.portc)) { #else if ((fd < 0) || (fd >= NELEMS (port))) { #endif DBG( 2, "sanei_pp_getmodes: invalid fd %d\n", fd ); return SANE_STATUS_INVAL; } if( mode ) *mode = port[fd].caps; return SANE_STATUS_GOOD; } SANE_Status sanei_pp_setmode( int fd, int mode ) { #if defined(HAVE_LIBIEEE1284) int result; if ((fd < 0) || (fd >= pplist.portc)) { #else if ((fd < 0) || (fd >= NELEMS (port))) { #endif DBG( 2, "sanei_pp_setmode: invalid fd %d\n", fd ); return SANE_STATUS_INVAL; } if((mode != SANEI_PP_MODE_SPP) && (mode != SANEI_PP_MODE_BIDI) && (mode != SANEI_PP_MODE_EPP) && (mode != SANEI_PP_MODE_ECP)) { DBG( 2, "sanei_pp_setmode: invalid mode %d\n", mode ); return SANE_STATUS_INVAL; } #if defined(HAVE_LIBIEEE1284) switch( mode ) { case SANEI_PP_MODE_SPP: mode = M1284_NIBBLE; break; case SANEI_PP_MODE_BIDI: mode = M1284_BYTE; break; case SANEI_PP_MODE_EPP: mode = M1284_EPP; break; case SANEI_PP_MODE_ECP: mode = M1284_ECP; break; default: DBG( 2, "sanei_pp_setmode: invalid mode %d\n", mode ); return SANE_STATUS_INVAL; } result = ieee1284_negotiate( pplist.portv[fd], mode ); /* negotiation might fails, but the port-mode should be set... */ if((E1284_OK != result) && (E1284_NEGFAILED != result)) { DBG( 2, "sanei_pp_setmode failed: %s\n", pp_libieee1284_errorstr( result )); return SANE_STATUS_INVAL; } return SANE_STATUS_GOOD; #else return pp_setmode( fd, mode ); #endif } void sanei_pp_udelay( unsigned long usec ) { struct timeval now, deadline; if( usec == 0 ) return; gettimeofday( &deadline, NULL ); deadline.tv_usec += usec; deadline.tv_sec += deadline.tv_usec / 1000000; deadline.tv_usec %= 1000000; if( usec < pp_thresh ) return; do { gettimeofday( &now, NULL ); } while ((now.tv_sec < deadline.tv_sec) || (now.tv_sec == deadline.tv_sec && now.tv_usec < deadline.tv_usec)); } SANE_Status sanei_pp_set_datadir( int fd, int rev ) { #if defined(HAVE_LIBIEEE1284) if ((fd < 0) || (fd >= pplist.portc)) { #else SANE_Byte tmp; if ((fd < 0) || (fd >= NELEMS (port))) { #endif DBG( 2, "sanei_pp_setdir: invalid fd %d\n", fd ); return SANE_STATUS_INVAL; } #if defined(HAVE_LIBIEEE1284) ieee1284_data_dir( pplist.portv[fd], rev ); #else tmp = inb_ctrl( fd ); if( SANEI_PP_DATAIN == rev ) tmp |= SANEI_PP_CTRL_DIRECTION; else tmp &= ~SANEI_PP_CTRL_DIRECTION; outb_ctrl( fd, tmp ); #endif return SANE_STATUS_GOOD; } SANE_Bool sanei_pp_uses_directio( void ) { #if defined(HAVE_LIBIEEE1284) return SANE_FALSE; #else return SANE_TRUE; #endif } #else /* !HAVE_IOPERM */ SANE_Status sanei_pp_init( void ) { DBG_INIT(); _VAR_NOT_USED( first_time ); return SANE_STATUS_GOOD; } SANE_Status sanei_pp_open( const char *dev, int *fd ) { if (fd) *fd = -1; DBG( 4, "sanei_pp_open: called for device `%s`\n", dev ); DBG( 3, "sanei_pp_open: support not compiled\n" ); DBG( 6, "sanei_pp_open: basically, this backend does only compile\n" ); DBG( 6, "sanei_pp_open: on x86 architectures. Furthermore it\n" ); DBG( 6, "sanei_pp_open: needs ioperm() and inb()/outb() calls.\n" ); DBG( 6, "sanei_pp_open: alternativly it makes use of libieee1284\n" ); DBG( 6, "sanei_pp_open: (which isn't present either)\n"); return SANE_STATUS_INVAL; } void sanei_pp_close( int fd ) { DBG( 4, "sanei_pp_close: called for fd %d\n", fd ); DBG( 2, "sanei_pp_close: fd %d is invalid\n", fd ); return; } SANE_Status sanei_pp_claim( int fd ) { DBG( 4, "sanei_pp_claim: called for fd %d\n", fd ); DBG( 2, "sanei_pp_claim: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } SANE_Status sanei_pp_release( int fd ) { DBG( 4, "sanei_pp_release: called for fd %d\n", fd ); DBG( 2, "sanei_pp_release: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } SANE_Status sanei_pp_outb_data( int fd, SANE_Byte val ) { _VAR_NOT_USED( val ); DBG( 4, "sanei_pp_outb_data: called for fd %d\n", fd ); DBG( 2, "sanei_pp_outb_data: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } SANE_Status sanei_pp_outb_ctrl( int fd, SANE_Byte val ) { _VAR_NOT_USED( val ); DBG( 4, "sanei_pp_outb_ctrl: called for fd %d\n", fd ); DBG( 2, "sanei_pp_outb_ctrl: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } SANE_Status sanei_pp_outb_addr( int fd, SANE_Byte val ) { _VAR_NOT_USED( val ); DBG( 4, "sanei_pp_outb_addr: called for fd %d\n", fd ); DBG( 2, "sanei_pp_outb_addr: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } SANE_Byte sanei_pp_inb_data( int fd ) { DBG( 4, "sanei_pp_inb_data: called for fd %d\n", fd ); DBG( 2, "sanei_pp_inb_data: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } SANE_Byte sanei_pp_inb_stat( int fd ) { DBG( 4, "sanei_pp_inb_stat: called for fd %d\n", fd ); DBG( 2, "sanei_pp_inb_stat: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } SANE_Byte sanei_pp_inb_ctrl( int fd ) { DBG( 4, "sanei_pp_inb_ctrl: called for fd %d\n", fd ); DBG( 2, "sanei_pp_inb_ctrl: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } SANE_Byte sanei_pp_inb_epp ( int fd ) { DBG( 4, "sanei_pp_inb_epp: called for fd %d\n", fd ); DBG( 2, "sanei_pp_inb_epp: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } SANE_Status sanei_pp_getmodes( int fd, int *mode ) { _VAR_NOT_USED( mode ); DBG( 4, "sanei_pp_getmodes: called for fd %d\n", fd ); DBG( 1, "sanei_pp_getmodes: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } SANE_Status sanei_pp_setmode( int fd, int mode ) { _VAR_NOT_USED( mode ); DBG( 4, "sanei_pp_setmode: called for fd %d\n", fd ); DBG( 1, "sanei_pp_setmode: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } void sanei_pp_udelay( unsigned long usec ) { _VAR_NOT_USED( usec ); _VAR_NOT_USED( pp_thresh ); DBG( 2, "sanei_pp_udelay: not supported\n" ); } SANE_Status sanei_pp_set_datadir( int fd, int rev ) { _VAR_NOT_USED( rev ); DBG( 4, "sanei_pp_setdir: called for fd %d\n", fd ); DBG( 1, "sanei_pp_setdir: fd %d is invalid\n", fd ); return SANE_STATUS_INVAL; } SANE_Bool sanei_pp_uses_directio( void ) { DBG( 1, "sanei_pp_uses_directio: not supported\n" ); return SANE_FALSE; } #endif /* !HAVE_IOPERM */