sane-project-backends/backend/umax_pp_low.c

7683 wiersze
168 KiB
C

/* sane - Scanner Access Now Easy.
Copyright (C) 2001 Stéphane Voltz <svoltz@wanadoo.fr>
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 a SANE backend for Umax PP flatbed scanners. */
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include "../include/sane/config.h"
#include "../include/sane/sanei_debug.h"
#include <errno.h>
#ifdef HAVE_LINUX_PPDEV_H
#include <sys/ioctl.h>
#include <linux/parport.h>
#include <linux/ppdev.h>
#endif
#if defined HAVE_SYS_IO_H && defined HAVE_IOPERM
# include <sys/io.h> /* GNU libc based Linux */
#elif HAVE_ASM_IO_H
# include <asm/io.h> /* older Linux */
#elif HAVE_SYS_HW_H
# include <sys/hw.h> /* OS/2 */
#elif defined(__i386__) && defined (__GNUC__)
/* other x86 with GCC (Win9x ?) */
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;
}
static __inline__ void
outsb (unsigned short port, const void *addr, unsigned long count)
{
__asm__ __volatile__ ("rep ; outsb":"=S" (addr), "=c" (count):"d" (port),
"0" (addr), "1" (count));
}
static __inline__ void
outsw (unsigned short port, const void *addr, unsigned long count)
{
__asm__ __volatile__ ("rep ; outsw":"=S" (addr), "=c" (count):"d" (port),
"0" (addr), "1" (count));
}
static __inline__ void
insb (unsigned short port, void *addr, unsigned long count) \
{
__asm__ __volatile__ ("rep ; insb":"=D" (addr), "=c" (count):"d" (port),
"0" (addr), "1" (count));
}
static __inline__ void
insl (unsigned short port, void *addr, unsigned long count) \
{
__asm__ __volatile__ ("rep ; insl":"=D" (addr), "=c" (count):"d" (port),
"0" (addr), "1" (count));
}
#else
#define IO_SUPPORT_MISSING
#endif
#include "umax_pp_low.h"
#ifndef __IO__
#define __IO__
#define DATA gPort+0x00
#define STATUS gPort+0x01
#define CONTROL gPort+0x02
#define EPPADR gPort+0x03
#define EPPDATA gPort+0x04
#define ECPCONTROL gPort+0x402
#endif
static int Fonc001 (void);
static int InitBuffer001 (void);
static int InitBuffer002 (void);
static int FoncSendWord (int *cmd);
static void SetEPPMode (int mode);
static int GetEPPMode (void);
static void SetModel (int model);
static int GetModel (void);
static int RingScanner (void);
static int TestVersion (int no);
static int SendCommand (int cmd);
static void SPPResetLPT (void);
static int SendWord (int *cmd);
static int SendData (int *cmd, int len);
static int ReceiveData (int *cmd, int len);
static int SendLength (int *cmd, int len);
static void Init001 (void);
static int Init002 (int arg);
static int Init004 (void);
static int Init005 (int arg);
static int Init021 (void);
static int Init022 (void);
static void NibbleReadBuffer (int size, unsigned char *dest);
static void WriteBuffer (int size, unsigned char *source);
static void EPPReadBuffer (int size, unsigned char *dest);
static void EPPWriteBuffer (int size, unsigned char *source);
static void EPPRead32Buffer (int size, unsigned char *dest);
static void InitPausedRead (void);
static int PausedReadBuffer (int size, unsigned char *dest);
static void EPPWrite32Buffer (int size, unsigned char *source);
static int SlowNibbleRegisterRead (int reg);
static int EPPRegisterRead (int reg);
static void ClearRegister (int reg);
static void WriteSlow (int reg, int value);
static void EPPRegisterWrite (int reg, int value);
static int Prologue (void);
static int Epilogue (void);
static int CmdSet (int cmd, int len, int *buffer);
static int CmdGet (int cmd, int len, int *buffer);
static int CmdSetGet (int cmd, int len, int *buffer);
static int CmdGetBuffer (int cmd, int len, unsigned char *buffer);
static int CmdGetBuffer32 (int cmd, int len, unsigned char *buffer);
static int CmdGetBlockBuffer (int cmd, int len, int window,
unsigned char *buffer);
static void Bloc2Decode (int *op);
static void Bloc8Decode (int *op);
#define WRITESLOW(x,y) \
WriteSlow((x),(y)); \
DBG(16,"WriteSlow(0x%X,0x%X) passed... (%s:%d)\n",(x),(y),__FILE__,__LINE__);
#define SLOWNIBBLEREGISTEREAD(x,y) \
tmp=SlowNibbleRegisterRead(x);\
if(tmp!=y)\
{\
DBG(0,"SlowNibbleRegisterRead: found 0x%X expected 0x%X (%s:%d)\n",tmp,y,__FILE__,__LINE__);\
/*return 0;*/ \
}\
DBG(16,"SlowNibbleRegisterRead(0x%X)=0x%X passed... (%s:%d)\n",x,y,__FILE__,__LINE__);
#define EPPREGISTERWRITE(x,y) \
EPPRegisterWrite((x),(y)); \
DBG(16,"EPPRegisterWrite(0x%X,0x%X) passed... (%s:%d)\n",(x),(y),__FILE__,__LINE__);
#define EPPREGISTERREAD(x,y) \
tmp=EPPRegisterRead(x);\
if(tmp!=y)\
{\
DBG(0,"EPPRegisterRead, found 0x%X expected 0x%X (%s:%d)\n",tmp,y,__FILE__,__LINE__);\
return 0;\
}\
DBG(16,"EPPRegisterRead(0x%X)=0x%X passed... (%s:%d)\n",x,y,__FILE__,__LINE__);
#define TRACE(level,msg) DBG(level, msg" (%s:%d)\n",__FILE__,__LINE__);
#define CMDSYNC(x) if(sanei_umax_pp_CmdSync(x)!=1)\
{\
DBG(0,"CmdSync(0x%02X) failed (%s:%d)\n",x,__FILE__,__LINE__);\
return(0);\
}\
TRACE(16,"CmdSync() passed ...")
#define CMDSETGET(cmd,len,sent) if(CmdSetGet(cmd,len,sent)!=1)\
{\
DBG(0,"CmdSetGet(0x%02X,%d,sent) failed (%s:%d)\n",cmd,len,__FILE__,__LINE__);\
return(0);\
}\
TRACE(16,"CmdSetGet() passed ...")
#define YOFFSET 40
#define YOFFSET1220P 40
#define YOFFSET2000P 40
#define COMPLETIONWAIT if(CompletionWait()==0)\
{\
DBG(0,"CompletionWait() failed (%s:%d)\n",__FILE__,__LINE__);\
return(0);\
}\
TRACE(16,"CompletionWait() passed ...")
#define MOVE(x,y,t) if(Move(x,y,t)==0)\
{\
DBG(0,"Move(%d,%d,buffer) failed (%s:%d)\n",x,y,__FILE__,__LINE__);\
return(0);\
}\
TRACE(16,"Move() passed ...")
#define CMDGETBUF(cmd,len,sent) if(CmdGetBuffer(cmd,len,sent)!=1)\
{\
DBG(0,"CmdGetBuffer(0x%02X,%ld,buffer) failed (%s:%d)\n",cmd,(long)len,__FILE__,__LINE__);\
return(0);\
}\
TRACE(16,"CmdGetBuffer() passed ...")
#define CMDGETBUF32(cmd,len,sent) if(CmdGetBuffer32(cmd,len,sent)!=1)\
{\
DBG(0,"CmdGetBuffer32(0x%02X,%ld,buffer) failed (%s:%d)\n",cmd,(long)len,__FILE__,__LINE__);\
return(0);\
}\
TRACE(16,"CmdGetBuffer32() passed ...")
#define CMDSET(cmd,len,sent) if(CmdSet(cmd,len,sent)!=1)\
{\
DBG(0,"CmdSet(0x%02X,%d,sent) failed (%s:%d)\n",cmd,len,__FILE__,__LINE__);\
return(0);\
}\
TRACE(16,"CmdSet() passed ...")
#define CMDGET(cmd,len,sent) if(CmdGet(cmd,len,sent)!=1)\
{\
DBG(0,"CmdGet(0x%02X,%d,read) failed (%s:%d)\n",cmd,len,__FILE__,__LINE__);\
return(0);\
}\
TRACE(16,"CmdGet() passed ...")
static int cmd1[] = { 0x00, 0x00, 0x22, 0x88, -1 };
static int cmd3[] = { 0x00, 0x08, 0x00, 0x84, -1 }; /* 2048 bytes size write */
static int cmd4[] = { 0x00, 0x08, 0x00, 0xC4, -1 }; /* 2048 bytes size read */
static int commande2[] = { 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C,
0x00, 0x03, 0xC1, 0x80, 0x00, 0x20, 0x02, 0x00,
0x16, 0x41, 0xE0, 0xAC, 0x03, 0x03, 0x00, 0x00,
0x46, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, -1
};
static int gPort = 0x378;
/* global control vars */
static int gControl = 0;
static int gData = 0;
static int g674 = 0; /* semble indiquer qu'on utilise les IRQ */
static int g67D = 0;
static int g67E = 0;
static int gEPAT = 0; /* signals fast mode ? */
static int g6FE = 0;
/* default gamma translation table */
static int ggamma[256] =
{ 0x00, 0x06, 0x0A, 0x0D, 0x10, 0x12, 0x14, 0x17, 0x19, 0x1B, 0x1D, 0x1F,
0x21, 0x23, 0x24, 0x26, 0x28, 0x2A, 0x2B, 0x2D, 0x2E, 0x30, 0x31, 0x33,
0x34, 0x36, 0x37, 0x39, 0x3A, 0x3B, 0x3D, 0x3E, 0x40, 0x41, 0x42, 0x43,
0x45, 0x46, 0x47, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4F, 0x50, 0x51, 0x52,
0x53, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5E, 0x5F, 0x60,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C,
0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84,
0x85, 0x86, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x97, 0x98, 0x99,
0x9A, 0x9B, 0x9C, 0x9D, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA2, 0xA3,
0xA4, 0xA5, 0xA6, 0xA7, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAC, 0xAD,
0xAE, 0xAF, 0xB0, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB4, 0xB5, 0xB6, 0xB7,
0xB8, 0xB8, 0xB9, 0xBA, 0xBB, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xBF, 0xC0,
0xC1, 0xC2, 0xC2, 0xC3, 0xC4, 0xC5, 0xC5, 0xC6, 0xC7, 0xC8, 0xC8, 0xC9,
0xCA, 0xCB, 0xCB, 0xCC, 0xCD, 0xCE, 0xCE, 0xCF, 0xD0, 0xD1, 0xD1, 0xD2,
0xD3, 0xD4, 0xD4, 0xD5, 0xD6, 0xD6, 0xD7, 0xD8, 0xD9, 0xD9, 0xDA, 0xDB,
0xDC, 0xDC, 0xDD, 0xDE, 0xDE, 0xDF, 0xE0, 0xE1, 0xE1, 0xE2, 0xE3, 0xE3,
0xE4, 0xE5, 0xE6, 0xE6, 0xE7, 0xE8, 0xE8, 0xE9, 0xEA, 0xEA, 0xEB, 0xEC,
0xEC, 0xED, 0xEE, 0xEF, 0xEF, 0xF0, 0xF1, 0xF1, 0xF2, 0xF3, 0xF3, 0xF4,
0xF5, 0xF5, 0xF6, 0xF7, 0xF7, 0xF8, 0xF9, 0xF9, 0xFA, 0xFB, 0xFB, 0xFC,
0xFD, 0xFE, 0xFE, 0xFF
};
/* default gamma translation table */
static int *ggGreen = ggamma;
static int *ggBlue = ggamma;
static int *ggRed = ggamma;
static int gParport = -1;
static int gCancel = 0;
/*****************************************************************************/
/* output one byte on given port */
/*****************************************************************************/
static void Outb (int port, int value);
/*****************************************************************************/
/* ouput 'size' bytes stored in 'source' on given port */
/*****************************************************************************/
static void Outsb (int port, unsigned char *source, int size);
/*****************************************************************************/
/* ouput 'size' 32 bits words stored in 'source' on given port */
/*****************************************************************************/
static void Outsw (int port, unsigned char *source, int size);
/*****************************************************************************/
/* input one byte from given port */
/*****************************************************************************/
static int Inb (int port);
/*****************************************************************************/
/* input 'size' bytes from given port ans store them in 'dest' */
/*****************************************************************************/
static void Insb (int port, unsigned char *dest, int size);
/*****************************************************************************/
/* input 'size' 32 bits word from given port ans store them in 'dest' */
/*****************************************************************************/
static void Insw (int port, unsigned char *dest, int size);
/*
* returns 1 if succeds in getting base addr via /proc
* 0 on failure
*
* on successfull return, *addr will hold parport base addr
*/
int
sanei_parport_info (int number, int *addr)
{
char name[256];
FILE *fic = NULL;
char buffer[64], val[16];
int baseadr, ecpadr;
/* try 2.4 first */
sprintf (name, "/proc/sys/dev/parport/parport%d/base-addr", number);
memset (buffer, 0, 64);
memset (val, 0, 16);
fic = fopen (name, "rb");
if (fic == NULL)
{
/* open failure, try 2.2 */
sprintf (name, "/proc/parport/%d/hardware", number);
fic = fopen (name, "rb");
if (fic == NULL)
{ /* no proc at all */
DBG (1, "sanei_parport_info(): no /proc \n");
return (0);
}
fread (buffer, 64, 1, fic);
fclose (fic);
sscanf (buffer, "base: %s", val);
baseadr = strtol (val, NULL, 16);
}
else
{
fread (buffer, 64, 1, fic);
fclose (fic);
if (sscanf (buffer, "%d %d", &baseadr, &ecpadr) < 1)
{
/* empty base file */
return (0);
}
*addr = baseadr;
}
return (1);
}
/*
* gain direct acces to IO port, and set parport to the 'right' mode
* returns 1 on success, 0 an failure
*/
int
sanei_umax_pp_InitPort (int port)
{
int spp_status;
int spp_control;
int spp_data;
#if ((defined HAVE_IOPERM)||(defined HAVE_LINUX_PPDEV_H))
int mode;
#endif
#ifdef HAVE_LINUX_PPDEV_H
char parport_name[16];
int i, found;
int value;
int ectr, addr;
#endif
int fd;
/* since this function must be called before */
/* any other, we put debug init here */
DBG_INIT ();
/* init global var holding port value */
gPort = port;
#ifdef IO_SUPPORT_MISSING
if (gPort) /* dummy test for compiler relief */
{
DBG (1, "*** Direct I/O unavailable, giving up ***\n");
return (0);
}
#else
#ifdef HAVE_IOPERM
if (ioperm (port, 8, 1) != 0)
{
DBG (1, "ioperm could not gain access to 0x%X\n", port);
return (0);
}
/* ECP i/o range */
if (iopl (3) != 0)
{
DBG (1, "iopl could not raise IO permission to level 3\n");
return (0);
}
mode = getuid ();
setreuid (mode, mode);
mode = getgid ();
setregid (mode, mode);
#endif
#ifdef HAVE_SYS_HW_H
/* gainig io perm under OS/2 */
/* IOPL must has been raised to 3 in config.sys */
/* for EMX portaccess always succeeds */
_portaccess (port, port + 7);
#endif
/* FreeBSD and NetBSD with compatibility opion 9 */
/* opening /dev/io raise IOPL to level 3 */
fd = open ("/dev/io", O_RDWR);
if (errno == EACCES)
{
/* /dev/io exist but process hasn't the right permission */
DBG (1, "/dev/io could not gain access to 0x%X\n", port);
return (0);
}
if ((errno == ENXIO) || (errno == ENOENT))
{
/* /dev/io does not exist */
DBG (16, "no '/dev/io' device\n");
}
else if (errno != 0)
{
/* /dev/io we get an unexpected error */
DBG (1, "opening '/dev/io' got unxepected errno=%d\n", errno);
return (0);
}
/* this ensures that the port is in the expected idle state */
/* only useful when doing effective hardware access */
spp_data = Inb (DATA);
spp_status = Inb (STATUS);
spp_control = Inb (CONTROL);
DBG (128, "START STATE:\n");
DBG (128, "\tport =0x%02X\n", port);
DBG (128, "\tdata =0x%02X\n", spp_data);
DBG (128, "\tstatus =0x%02X\n", spp_status);
DBG (128, "\tcontrol=0x%02X\n", spp_control);
if (spp_data != 0x04)
Outb (0x04, DATA);
if (spp_control != 0xCC)
{
spp_control = spp_control & 0x1F;
Outb (0x0C, CONTROL);
}
#endif
#ifdef HAVE_LINUX_PPDEV_H
/* ppdev opening and configuration */
/* we start with /dev/parport0 and go through all /dev/parportx */
/* until we find the right one */
i = 0;
found = 0;
sprintf (parport_name, "/dev/parport%d", i);
fd = open (parport_name, O_RDONLY | O_NOCTTY);
while ((fd != -1) && (!found))
{
/* claim port */
if (ioctl (fd, PPCLAIM))
{
DBG (1, "umax_pp: cannot claim port '%s'\n", parport_name);
}
else
{
/* we check if parport is does ECP */
#ifdef PPGETMODES
if (ioctl (fd, PPGETMODES, &mode))
{
DBG (16, "umax_pp: ppdev couldn't gave modes for port '%s'\n",
parport_name);
}
else
{
DBG (32, "parport modes: %X\n", mode);
if (mode & PARPORT_MODE_ECP)
{
DBG (16, "umax_pp: initializing ECPEPP\n");
/* set up ECPEPP the hard way ... */
/* frob_econtrol (port, 0xe0, 4 << 5);
unsigned char ectr = inb (ECONTROL (pb));
outb ((ectr & ~m) ^ v, ECONTROL (pb)); */
ectr = Inb (ECPCONTROL);
ectr = (ectr & ~(0xE0)) ^ (4 << 5);
Outb (ECPCONTROL, ectr);
}
if (!(mode & PARPORT_MODE_ECP) && !(mode & PARPORT_MODE_ECP))
{
DBG (1,
"port 0x%X does not have EPP or ECP, giving up ...\n",
port);
return (0);
}
}
#else
DBG (16, "umax_pp: ppdev used to build SANE doesn't have PPGETMODES.\n");
#endif
/* find the base addr of ppdev */
if (sanei_parport_info (i, &addr))
{
if (gPort == addr)
{
found = 1;
DBG (1, "Using /proc info\n");
}
}
else
{
/* write to DATA via direct io and read DATA via parport */
/* if values match, we found the right parport */
Outb (DATA, 0x5A);
if (ioctl (fd, PPRDATA, &value))
{
DBG (16, "umax_pp: cannot read data from port <%s>\n",
parport_name);
}
value &= 0xFF;
if (value == 0x5A)
{
found = 1;
DBG (1, "Using '%s'.\n", parport_name);
}
}
/* release port */
mode = IEEE1284_MODE_COMPAT;
ioctl (fd, PPSETMODE, &mode);
ioctl (fd, PPRELEASE);
}
/* next parport */
if (!found)
{
close (fd);
i++;
sprintf (parport_name, "/dev/parport%d", i);
fd = open (parport_name, O_RDONLY | O_NOCTTY);
}
}
if (!found)
{
DBG (1, "no relevant /dev/parportx found...\n");
}
else
{
gParport = fd;
}
#endif
return (1);
}
static void
Outb (int port, int value)
{
#ifndef IO_SUPPORT_MISSING
#ifdef HAVE_SYS_HW_H
_outp8 (port, value);
#else
outb (value, port);
#endif
#endif
}
static int
Inb (int port)
{
int res = 0xFF;
#ifndef IO_SUPPORT_MISSING
#ifdef HAVE_SYS_HW_H
res = _inp8 (port) & 0xFF;
#else
res = inb (port) & 0xFF;
#endif
#endif
return res;
}
static void
Insb (int port, unsigned char *dest, int size)
{
#ifndef IO_SUPPORT_MISSING
#ifndef __i386__
int i;
for (i = 0; i < size; i++)
dest[i] = Inb (port);
#else
#ifdef HAVE_SYS_HW_H
_inps8 (port, dest, size);
#else
insb (port, dest, size);
#endif
#endif
#endif
}
static void
Outsb (int port, unsigned char *source, int size)
{
#ifndef IO_SUPPORT_MISSING
#ifndef __i386__
int i;
for (i = 0; i < size; i++)
Outb (port, source[i]);
#else
#ifdef HAVE_SYS_HW_H
_outps8 (port, source, size);
#else
outsb (port, source, size);
#endif
#endif
#endif
}
/* size = nb words */
static void
Insw (int port, unsigned char *dest, int size)
{
#ifndef IO_SUPPORT_MISSING
#ifndef __i386__
int i;
for (i = 0; i < size * 4; i++)
dest[i] = Inb (port);
#else
#ifdef HAVE_SYS_HW_H
_inps32 (port, (unsigned long *) dest, size);
#else
insl (port, dest, size);
#endif
#endif
#endif
}
static void
Outsw (int port, unsigned char *source, int size)
{
#ifndef IO_SUPPORT_MISSING
#ifndef __i386__
int i;
for (i = 0; i < size * 4; i++)
Outb (port, source[i]);
#else
#ifdef HAVE_SYS_HW_H
_outps32 (port, (unsigned long *) source, size);
#else
outsw (port, source, size);
#endif
#endif
#endif
}
/* we're trying to gather information on the scanner here, */
/* and published it through an easy interface */
static int scannerStatus = 0;
static int epp32 = 1;
static int model = 0x15;
static int astra = 1220;
int
sanei_umax_pp_ScannerStatus (void)
{
/* 0x07 variant returns status with bit 0 or 1 allways set to 1 */
/* so we mask it out */
return (scannerStatus & 0xFC);
}
static int
GetEPPMode (void)
{
if (epp32)
return (32);
return (8);
}
static void
SetEPPMode (int mode)
{
if (mode == 8)
epp32 = 0;
else
epp32 = 1;
}
static int
GetModel (void)
{
return (model);
}
static void
SetModel (int mod)
{
model = mod;
}
int
sanei_umax_pp_getparport (void)
{
return (gParport);
}
void
sanei_umax_pp_setparport (int fd)
{
gParport = fd;
}
int
sanei_umax_pp_getport (void)
{
return (gPort);
}
void
sanei_umax_pp_setport (int port)
{
gPort = port;
}
int
sanei_umax_pp_getastra (void)
{
return (astra);
}
void
sanei_umax_pp_setastra (int mod)
{
astra = mod;
}
static int
NibbleRead (void)
{
int res;
int tmp;
res = Inb (STATUS);
res = Inb (STATUS);
res = res & 0xF0;
Outb (CONTROL, 5);
Outb (CONTROL, 5);
Outb (CONTROL, 5);
Outb (CONTROL, 5);
Outb (CONTROL, 5);
Outb (CONTROL, 5);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
tmp = Inb (STATUS);
tmp = Inb (STATUS);
tmp = (tmp & 0xF0) >> 4;
res = res | tmp;
Outb (CONTROL, 5);
Outb (CONTROL, 5);
Outb (CONTROL, 5);
Outb (CONTROL, 5);
Outb (CONTROL, 5);
Outb (CONTROL, 5);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
return res;
}
/******************************************************************************/
/* WriteSlow: write value in register, slow method */
/******************************************************************************/
static void
WriteSlow (int reg, int value)
{
/* select register */
Outb (DATA, reg | 0x60);
Outb (DATA, reg | 0x60);
Outb (CONTROL, 0x01);
Outb (CONTROL, 0x01);
Outb (CONTROL, 0x01);
/* send value */
Outb (DATA, value);
Outb (DATA, value);
Outb (CONTROL, 0x04);
Outb (CONTROL, 0x04);
Outb (CONTROL, 0x04);
}
/*****************************************************************************/
/* Send command returns 0 on failure, 1 on success */
/*****************************************************************************/
static int
SendCommand (int cmd)
{
int control;
int tmp;
int val;
int i;
int gReadBuffer[256]; /* read buffer for command 0x10 */
if (g674 != 0)
{
DBG (0, "No scanner attached, SendCommand(0x%X) failed\n", cmd);
return 0;
}
control = Inb (CONTROL) & 0x3F;
tmp = cmd & 0xF8;
if ((g67D != 1) && (tmp != 0xE0) && (tmp != 0x20) && (tmp != 0x40)
&& (tmp != 0xD0) && (tmp != 0x08) && (tmp != 0x48))
{
Outb (CONTROL, 4); /* reset printer */
}
else
{
val = control & 0x1F;
if (g67D != 1)
val = val & 0xF; /* no IRQ */
val = val | 0x4;
Outb (CONTROL, val);
Outb (CONTROL, val);
}
/* send sequence */
Outb (DATA, 0x22);
Outb (DATA, 0x22);
Outb (DATA, 0xAA);
Outb (DATA, 0xAA);
Outb (DATA, 0x55);
Outb (DATA, 0x55);
Outb (DATA, 0x00);
Outb (DATA, 0x00);
Outb (DATA, 0xFF);
Outb (DATA, 0xFF);
Outb (DATA, 0x87);
Outb (DATA, 0x87);
Outb (DATA, 0x78);
Outb (DATA, 0x78);
Outb (DATA, cmd);
Outb (DATA, cmd);
cmd = cmd & 0xF8;
if ((g67D == 1) && (cmd == 0xE0))
{
val = Inb (CONTROL);
val = (val & 0xC) | 0x01;
Outb (CONTROL, val);
Outb (CONTROL, val);
val = val & 0xC;
Outb (CONTROL, val);
Outb (CONTROL, val);
goto SendCommandEnd;
}
if ((cmd != 8) && (cmd != 0x48))
{
tmp = Inb (CONTROL);
tmp = Inb (CONTROL);
tmp = tmp & 0x1E;
if (g67D != 1)
tmp = tmp & 0xE;
Outb (CONTROL, tmp);
Outb (CONTROL, tmp);
}
if (cmd == 0x10)
{
tmp = NibbleRead ();
tmp = tmp * 256 + NibbleRead ();
goto SendCommandEnd;
}
if (cmd == 8)
{
if (g67D == 1)
{
i = 0;
while (i < g67E)
{
tmp = Inb (CONTROL);
tmp = Inb (CONTROL);
tmp = (tmp & 0x1E) | 0x1;
Outb (CONTROL, tmp);
Outb (CONTROL, tmp);
gReadBuffer[i] = Inb (STATUS);
tmp = tmp & 0x1E;
Outb (CONTROL, tmp);
Outb (CONTROL, tmp);
/* next read */
i++;
if (i < g67E)
{
Outb (DATA, i | 8);
Outb (DATA, i | 8);
}
}
goto SendCommandEnd;
}
else
{
DBG (0, "UNEXPLORED BRANCH %s:%d\n", __FILE__, __LINE__);
return 0;
}
}
/* */
if (cmd == 0)
{
i = 0;
do
{
tmp = Inb (CONTROL);
tmp = (tmp & 0xE) | 0x1;
Outb (CONTROL, tmp);
Outb (CONTROL, tmp);
tmp = tmp & 0xE;
Outb (CONTROL, tmp);
Outb (CONTROL, tmp);
i++;
if (i < g67E)
{
Outb (DATA, i);
Outb (DATA, i);
}
}
while (i < g67E);
goto SendCommandEnd;
}
if (cmd == 0x48)
{
/* this case is unneeded, should fit with the rest */
tmp = Inb (CONTROL) & 0x1E;
if (g67D != 1)
tmp = tmp & 0xE;
Outb (CONTROL, tmp | 0x1);
Outb (CONTROL, tmp | 0x1);
Outb (CONTROL, tmp);
Outb (CONTROL, tmp);
goto SendCommandEnd;
}
/* */
tmp = Inb (CONTROL) & 0x1E;
if (g67D != 1)
tmp = tmp & 0xE;
Outb (CONTROL, tmp | 0x1);
Outb (CONTROL, tmp | 0x1);
Outb (CONTROL, tmp);
Outb (CONTROL, tmp);
/* success */
SendCommandEnd:
if (cmd == 0x48)
Outb (CONTROL, (control & 0xF) | 0x4);
if (cmd == 0x30)
Outb (CONTROL, (gControl & 0xF) | 0x4);
/* end signature */
Outb (DATA, 0xFF);
Outb (DATA, 0xFF);
if (cmd == 8)
{
Outb (CONTROL, control);
return 1;
}
if (cmd == 0x30)
{
Outb (CONTROL, gControl);
return 1;
}
if (cmd != 0xE0)
Outb (CONTROL, control);
return 1;
}
static void
ClearRegister (int reg)
{
/* choose register */
Outb (DATA, reg);
Outb (DATA, reg);
Outb (CONTROL, 1);
Outb (CONTROL, 1);
if ((g6FE == 0) || (g674 != 0))
{
Outb (CONTROL, 1);
Outb (CONTROL, 1);
Outb (CONTROL, 1);
Outb (CONTROL, 1);
}
/* clears it by not sending new value */
Outb (CONTROL, 4);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
}
static void
SPPResetLPT (void)
{
Outb (CONTROL, 0x04);
}
static int
SlowNibbleRegisterRead (int reg)
{
int low, high;
/* send register number */
Outb (DATA, reg);
Outb (DATA, reg);
/* get low nibble */
Outb (CONTROL, 1);
Outb (CONTROL, 3);
Outb (CONTROL, 3);
Outb (CONTROL, 3);
Outb (CONTROL, 3);
low = Inb (STATUS);
low = Inb (STATUS);
/* get high nibble */
Outb (CONTROL, 4);
Outb (CONTROL, 4);
Outb (CONTROL, 4);
high = Inb (STATUS);
high = Inb (STATUS);
/* merge nibbles and return */
high = (high & 0xF0) | ((low & 0xF0) >> 4);
return (high);
}
static void
NibbleReadBuffer (int size, unsigned char *dest)
{
int high;
int low;
int i;
int count;
int bytel, byteh;
/* init transfer */
Outb (DATA, 7);
Outb (DATA, 7);
Outb (CONTROL, 1);
Outb (CONTROL, 1);
Outb (CONTROL, 3);
Outb (CONTROL, 3);
Outb (CONTROL, 3);
Outb (DATA, 0xFF);
Outb (DATA, 0xFF);
count = (size - 2) / 2;
i = 0;
bytel = 0x06; /* signals low byte of word */
byteh = 0x07; /* signals high byte of word */
/* read loop */
while (count > 0)
{
/* low nibble byte 0 */
Outb (CONTROL, bytel);
Outb (CONTROL, bytel);
Outb (CONTROL, bytel);
low = Inb (STATUS);
if ((low & 0x08) == 0)
{
/* high nibble <> low nibble */
Outb (CONTROL, bytel & 0x05);
Outb (CONTROL, bytel & 0x05);
Outb (CONTROL, bytel & 0x05);
high = Inb (STATUS);
}
else
{
high = low;
}
low = low & 0xF0;
high = high & 0xF0;
dest[i] = (unsigned char) (high | (low >> 4));
i++;
/* low nibble byte 1 */
Outb (CONTROL, byteh);
Outb (CONTROL, byteh);
Outb (CONTROL, byteh);
low = Inb (STATUS);
if ((low & 0x08) == 0)
{
/* high nibble <> low nibble */
Outb (CONTROL, byteh & 0x05);
Outb (CONTROL, byteh & 0x05);
Outb (CONTROL, byteh & 0x05);
high = Inb (STATUS);
}
else
{
high = low;
}
low = low & 0xF0;
high = high & 0xF0;
dest[i] = (unsigned char) (high | (low >> 4));
i++;
/* next read */
count--;
}
/* final read */
/* low nibble byte 0 */
Outb (CONTROL, bytel);
Outb (CONTROL, bytel);
Outb (CONTROL, bytel);
low = Inb (STATUS);
if ((low & 0x08) == 0)
{
/* high nibble <> low nibble */
Outb (CONTROL, bytel & 0x05);
Outb (CONTROL, bytel & 0x05);
Outb (CONTROL, bytel & 0x05);
high = Inb (STATUS);
}
else
{
high = low;
}
low = low & 0xF0;
high = high & 0xF0;
dest[i] = (unsigned char) (high | (low >> 4));
i++;
/* uneven size need an extra read */
if ((size & 0x01) == 1)
{
/* low nibble byte 1 */
Outb (CONTROL, byteh);
Outb (CONTROL, byteh);
Outb (CONTROL, byteh);
low = Inb (STATUS);
if ((low & 0x08) == 0)
{
/* high nibble <> low nibble */
Outb (CONTROL, byteh & 0x05);
Outb (CONTROL, byteh & 0x05);
Outb (CONTROL, byteh & 0x05);
high = Inb (STATUS);
}
else
{
high = low;
}
low = low & 0xF0;
high = high & 0xF0;
dest[i] = (unsigned char) (high | (low >> 4));
i++;
/* swap high/low word */
count = bytel;
bytel = byteh;
byteh = count;
}
/* final byte ... */
Outb (DATA, 0xFD);
Outb (DATA, 0xFD);
Outb (DATA, 0xFD);
/* low nibble */
Outb (CONTROL, byteh);
Outb (CONTROL, byteh);
Outb (CONTROL, byteh);
low = Inb (STATUS);
if ((low & 0x08) == 0)
{
/* high nibble <> low nibble */
Outb (CONTROL, byteh & 0x05);
Outb (CONTROL, byteh & 0x05);
Outb (CONTROL, byteh & 0x05);
high = Inb (STATUS);
}
else
{
high = low;
}
low = low & 0xF0;
high = high & 0xF0;
dest[i] = (unsigned char) (high | (low >> 4));
i++;
/* reset port */
Outb (DATA, 0x00);
Outb (DATA, 0x00);
Outb (CONTROL, 0x04);
}
static void
WriteBuffer (int size, unsigned char *source)
{
int i;
int count;
int val;
/* init buffer write */
i = 0;
count = size / 2;
Outb (DATA, 0x67);
Outb (CONTROL, 0x01);
Outb (CONTROL, 0x01);
Outb (CONTROL, 0x05);
/* write loop */
while (count > 0)
{
/* low byte of word */
val = source[i];
i++;
Outb (DATA, val);
Outb (DATA, val);
Outb (CONTROL, 0x04);
Outb (CONTROL, 0x04);
Outb (CONTROL, 0x04);
Outb (CONTROL, 0x04);
/* high byte of word */
val = source[i];
i++;
Outb (DATA, val);
Outb (DATA, val);
Outb (CONTROL, 0x05);
Outb (CONTROL, 0x05);
Outb (CONTROL, 0x05);
Outb (CONTROL, 0x05);
/* next write */
count--;
}
/* termination sequence */
Outb (CONTROL, 0x05);
Outb (CONTROL, 0x05);
Outb (CONTROL, 0x05);
Outb (CONTROL, 0x05);
Outb (CONTROL, 0x07);
Outb (CONTROL, 0x07);
Outb (CONTROL, 0x07);
Outb (CONTROL, 0x07);
Outb (CONTROL, 0x04);
Outb (CONTROL, 0x04);
}
static void
Init001 (void)
{
int i;
int val;
int status;
ClearRegister (0);
Outb (CONTROL, 0x0C);
if (g674 != 0)
{
Outb (CONTROL, 0x0C);
Outb (CONTROL, 0x0C);
Outb (CONTROL, 0x0C);
}
Outb (DATA, 0x40);
if (g674 != 0)
{
Outb (DATA, 0x40);
Outb (DATA, 0x40);
Outb (DATA, 0x40);
}
Outb (CONTROL, 0x06);
Outb (CONTROL, 0x06);
Outb (CONTROL, 0x06);
if (g674 != 0)
{
Outb (CONTROL, 0x06);
Outb (CONTROL, 0x06);
Outb (CONTROL, 0x06);
}
/* sync loop */
i = 256;
do
{
status = Inb (STATUS);
i--;
}
while ((i > 0) && ((status & 0x40)));
val = 0x0C;
if (i > 0)
{
Outb (CONTROL, 0x07);
Outb (CONTROL, 0x07);
Outb (CONTROL, 0x07);
if (g674 != 0)
{
Outb (CONTROL, 0x07);
Outb (CONTROL, 0x07);
Outb (CONTROL, 0x07);
}
val = 0x04;
Outb (CONTROL, val);
Outb (CONTROL, val);
Outb (CONTROL, val);
if (g674 != 0)
{
Outb (CONTROL, val);
Outb (CONTROL, val);
Outb (CONTROL, val);
}
}
val = val | 0x0C;
Outb (CONTROL, val);
Outb (CONTROL, val);
Outb (CONTROL, val);
if (g674 != 0)
{
Outb (CONTROL, val);
Outb (CONTROL, val);
Outb (CONTROL, val);
}
val = val & 0xF7;
Outb (CONTROL, val);
Outb (CONTROL, val);
Outb (CONTROL, val);
if (g674 != 0)
{
Outb (CONTROL, val);
Outb (CONTROL, val);
Outb (CONTROL, val);
}
}
/* SPP register reading */
static int
Init002 (int arg)
{
int data;
if (arg == 1)
return (0);
Outb (DATA, 0x0B);
Outb (CONTROL, 0x04);
Outb (CONTROL, 0x04);
Outb (CONTROL, 0x04);
Outb (CONTROL, 0x0C);
Outb (CONTROL, 0x0C);
Outb (CONTROL, 0x0C);
Outb (CONTROL, 0x04);
Outb (CONTROL, 0x24);
Outb (CONTROL, 0x24);
Outb (CONTROL, 0x26);
Outb (CONTROL, 0x26);
data = Inb (DATA);
Outb (CONTROL, 0x04);
if (data == gEPAT)
{
return (1);
}
return (0);
}
static int
EPPRegisterRead (int reg)
{
int control;
int value;
Outb (EPPADR, reg);
control = Inb (CONTROL);
control = (control & 0x1F) | 0x20;
Outb (CONTROL, control);
value = Inb (EPPDATA);
control = Inb (CONTROL);
control = control & 0x1F;
Outb (CONTROL, control);
return (value);
}
static void
EPPRegisterWrite (int reg, int value)
{
reg = reg | 0x40;
Outb (EPPADR, reg);
Outb (EPPDATA, value);
}
static void
EPPReadBuffer (int size, unsigned char *dest)
{
int control;
Outb (EPPADR, 0x80);
control = Inb (CONTROL);
Outb (CONTROL, (control & 0x1F) | 0x20);
Insb (EPPDATA, dest, size - 1);
control = Inb (CONTROL);
Outb (CONTROL, (control & 0x1F));
Outb (EPPADR, 0xA0);
control = Inb (CONTROL);
Outb (CONTROL, (control & 0x1F) | 0x20);
Insb (EPPDATA, (unsigned char *) (dest + size - 1), 1);
control = Inb (CONTROL);
Outb (CONTROL, (control & 0x1F));
}
static void
EPPWriteBuffer (int size, unsigned char *source)
{
Outb (EPPADR, 0xC0);
Outsb (EPPDATA, source, size);
}
/* returns 0 if mode OK, else -1 */
static int
Init004 (void)
{
int control;
int mode;
Outb (EPPADR, 0x0B);
control = Inb (CONTROL);
Outb (CONTROL, (control & 0x1F) | 0x20);
mode = Inb (CONTROL + 5);
control = Inb (CONTROL);
Outb (CONTROL, (control & 0x1F));
if (mode == 0xC7)
return (0);
DBG (0, "Init004: expected 0xC7, got 0x%X! (%s:%d)\n", mode, __FILE__,
__LINE__);
return (-1);
}
static int
Init005 (int arg)
{
int count = 5;
int res;
while (count > 0)
{
EPPRegisterWrite (0x0A, arg);
Outb (DATA, 0xFF);
res = EPPRegisterRead (0x0A);
/* failed ? */
if (res != arg)
return (1);
/* ror arg */
res = arg & 0x01;
arg = arg / 2;
if (res == 1)
arg = arg | 0x80;
/* next loop */
count--;
}
return (0);
}
static void
Init020 (void)
{
int control;
int data;
Outb (DATA, 0x04);
Outb (CONTROL, 0x0C);
data = Inb (DATA);
control = Inb (CONTROL);
Outb (CONTROL, control & 0x1F);
control = Inb (CONTROL);
Outb (CONTROL, control & 0x1F);
}
/* 1 OK, 0 failure */
static int
Init021 (void)
{
Init020 ();
if (SendCommand (0xE0) != 1)
{
DBG (0, "Init021: SendCommand(0xE0) failed! (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
ClearRegister (0);
Init001 ();
return (1);
}
/* 1 OK, 0 failure */
static int
Init022 (void)
{
if (Init021 () != 1)
{
DBG (0, "Init022: Init021() failed! (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
return (1);
}
static void
EPPRead32Buffer (int size, unsigned char *dest)
{
int control;
Outb (EPPADR, 0x80);
/* beurk XXX STEF XXX */
/* but hides away outb in other functions */
if (size == 0)
return;
control = Inb (CONTROL);
Outb (CONTROL, (control & 0x1F) | 0x20);
Insw (EPPDATA, dest, size / 4 - 1);
Insb (EPPDATA, (unsigned char *) (dest + size - 4), 3);
control = Inb (CONTROL);
Outb (CONTROL, (control & 0x1F));
Outb (EPPADR, 0xA0);
control = Inb (CONTROL);
Outb (CONTROL, (control & 0x1F) | 0x20);
Insb (EPPDATA, (unsigned char *) (dest + size - 1), 1);
control = Inb (CONTROL);
Outb (CONTROL, (control & 0x1F));
}
static void
EPPWrite32Buffer (int size, unsigned char *source)
{
if ((size % 4) != 0)
{
DBG (0, "EPPWrite32Buffer: size %% 4 != 0!! (%s:%d)\n", __FILE__,
__LINE__);
}
Outb (EPPADR, 0xC0);
Outsw (EPPDATA, source, size / 4);
}
/* returns 0 if ERROR cleared in STATUS within 1024 inb, else 1 */
static int
WaitOnError (void)
{
int c = 0;
int count = 1024;
int status;
do
{
do
{
status = Inb (STATUS) & 0x08;
if (status != 0)
{
count--;
if (count == 0)
c = 1;
}
}
while ((count > 0) && (status != 0));
if (status == 0)
{
status = Inb (STATUS) & 0x08;
if (status == 0)
c = 0;
}
}
while ((status != 0) && (c == 0));
return (c);
}
/* read up to size bytes, returns bytes read */
static int
PausedReadBuffer (int size, unsigned char *dest)
{
int control;
int status;
int error;
int word;
int read;
int c;
/* init */
read = 0;
error = 0;
control = Inb (CONTROL) & 0x1F;
Outb (CONTROL, control | 0x20);
if ((size & 0x03) != 0)
{
/* 8174 */
while ((!error) && ((size & 0x03) != 0))
{
Insb (EPPDATA, dest, 1);
size--;
dest++;
read++;
status = Inb (STATUS) & 0x1F;
error = status & 0x08;
}
if (error)
{
DBG (0, "Read error (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
}
/* from here, we read 1 byte, then size/4-1 32 bits words, and then
3 bytes, pausing on ERROR bit of STATUS */
size -= 4;
/* sanity test, seems to be wrongly handled ... */
if (size == 0)
{
DBG (0, "case not handled! (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
word = 0;
error = 0;
read += size;
do
{
do
{
Insb (EPPDATA, dest, 1);
size--;
dest++;
readstatus:
if (size > 0)
{
status = Inb (STATUS) & 0x1F;
word = status & 0x10;
error = status & 0x08;
}
}
while ((size > 0) && (!error) && (!word));
}
while ((size < 4) && (!error) && (size > 0));
/* here size=0 or error=8 or word=0x10 */
if ((word) && (!error) && (size))
{
if (epp32)
Insw (EPPDATA, dest, 1);
else
Insb (EPPDATA, dest, 4);
dest += 4;
size -= 4;
if (size != 0)
error = 0x08;
}
if (!error)
{
c = 0;
error = Inb (STATUS) & 0x08;
if (error)
c = WaitOnError ();
}
else
{ /* 8282 */
c = WaitOnError ();
if (c == 0)
goto readstatus;
}
if (c == 1)
{
read -= size;
}
else
{
read += 3;
size = 3;
do
{
do
{
Insb (EPPDATA, dest, 1);
dest++;
size--;
if (size)
{
error = Inb (STATUS) & 0x08;
if (!error)
error = Inb (STATUS) & 0x08;
}
}
while ((size > 0) && (!error));
c = 0;
if (error)
c = WaitOnError ();
}
while ((size > 0) && (c == 0));
}
/* end reading */
control = Inb (CONTROL) & 0x1F;
Outb (CONTROL, control);
Outb (EPPADR, 0xA0);
control = Inb (CONTROL) & 0x1F;
Outb (CONTROL, control | 0x20);
Insb (EPPDATA, dest, 1);
read++;
control = Inb (CONTROL) & 0x1F;
Outb (CONTROL, control);
return (read);
}
/* returns 1 on success, 0 otherwise */
static int
SendWord1220P (int *cmd)
{
int i;
int reg;
int try = 0;
/* send header */
reg = EPPRegisterRead (0x19) & 0xF8;
retry:
EPPRegisterWrite (0x1C, 0x55);
reg = EPPRegisterRead (0x19) & 0xF8;
EPPRegisterWrite (0x1C, 0xAA);
reg = EPPRegisterRead (0x19) & 0xF8;
/* sync when needed */
if ((reg & 0x08) == 0x00)
{
reg = EPPRegisterRead (0x1C);
if ((reg & 0x10) != 0x10)
{
DBG (0, "SendWord failed (reg1C=0x%02X) (%s:%d)\n", reg, __FILE__,
__LINE__);
return (0);
}
for (i = 0; i < 10; i++)
{
usleep (1000);
reg = EPPRegisterRead (0x19) & 0xF8;
if (reg != 0xC8)
{
DBG (0, "Unexpected reg19=0x%2X (%s:%d)\n", reg, __FILE__,
__LINE__);
}
}
do
{
if ((reg != 0xC0) && (reg != 0xC8))
{
DBG (0, "Unexpected reg19=0x%2X (%s:%d)\n", reg, __FILE__,
__LINE__);
}
/* 0xF0 certainly means error */
if ((reg == 0xC0) || (reg == 0xD0))
{
try++;
goto retry;
}
reg = EPPRegisterRead (0x19) & 0xF8;
}
while (reg != 0xC8);
}
/* send word */
i = 0;
while ((reg == 0xC8) && (cmd[i] != -1))
{
EPPRegisterWrite (0x1C, cmd[i]);
i++;
reg = EPPRegisterRead (0x19) & 0xF8;
}
TRACE (16, "SendWord() passed ");
if ((reg != 0xC0) && (reg != 0xD0))
{
DBG (0, "SendWord failed got 0x%02X instead of 0xC0 or 0xD0 (%s:%d)\n",
reg, __FILE__, __LINE__);
DBG (0, "Blindly going on .....\n");
}
if (((reg == 0xC0) || (reg == 0xD0)) && (cmd[i] != -1))
{
DBG (0, "SendWord failed: short send (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
reg = EPPRegisterRead (0x1C);
DBG (16, "SendWord, reg1C=0x%02X (%s:%d)\n", reg, __FILE__, __LINE__);
/* model 0x07 has always the last bit set to 1, and even bit 1 */
scannerStatus = reg & 0xFC;
reg = reg & 0x10;
if (reg != 0x10)
{
DBG (0, "SendWord failed: acknowledge not received (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
if (try)
{
DBG (0, "SendWord retry success (retry %d time%s) ... (%s:%d)\n", try,
(try > 1) ? "s" : "", __FILE__, __LINE__);
}
return (1);
}
/* returns 1 on success, 0 otherwise */
static int
SendWord610P (int *cmd)
{
int i;
int tmp;
Outb (CONTROL, 0x05);
tmp = Inb (CONTROL);
Outb (CONTROL, 0x04);
/* send magic tag */
tmp = Inb (STATUS);
if (tmp != 0xC8)
{
DBG (0,
"SendWord610P failed, expected tmp=0xC8 , found 0x%02X (%s:%d)\n",
tmp, __FILE__, __LINE__);
return (0);
}
tmp = Inb (CONTROL);
Outb (CONTROL, 0x04);
Outb (EPPDATA, 0x55);
tmp = Inb (STATUS);
if (tmp != 0xC8)
{
DBG (0,
"SendWord610P failed, expected tmp=0xC8 , found 0x%02X (%s:%d)\n",
tmp, __FILE__, __LINE__);
return (0);
}
tmp = Inb (CONTROL);
Outb (CONTROL, 0x04);
Outb (EPPDATA, 0xAA);
tmp = Inb (CONTROL);
Outb (CONTROL, 0xA4);
for (i = 0; i < 9; i++)
{
tmp = Inb (STATUS);
if (tmp != 0xC8)
{
DBG (0,
"SendWord610P failed, expected tmp=0xC8 , found 0x%02X (%s:%d)\n",
tmp, __FILE__, __LINE__);
return (0);
}
}
i = 0;
while ((tmp == 0xC8) && (cmd[i] != -1))
{
tmp = Inb (STATUS);
Inb (CONTROL);
Outb (CONTROL, 0x04);
Outb (EPPDATA, cmd[i]);
}
/* end */
Outb (DATA, 0xFF);
tmp = Inb (CONTROL);
Outb (CONTROL, 0xA4);
tmp = Inb (STATUS);
if ((tmp != 0xC0) && (tmp != 0xD0))
{
DBG (0,
"SendWord610P failed got 0x%02X instead of 0xC0 or 0xD0 (%s:%d)\n",
tmp, __FILE__, __LINE__);
DBG (0, "Blindly going on .....\n");
}
tmp = Inb (EPPDATA);
scannerStatus = tmp;
return (1);
}
/*
* 0: failure
* 1: success
*/
static int
SendWord (int *cmd)
{
switch (sanei_umax_pp_getastra ())
{
case 610:
return (SendWord610P (cmd));
case 1220:
case 1600:
case 2000:
return (SendWord1220P (cmd));
}
return (0);
}
static void
InitPausedRead (void)
{
Outb (EPPADR, 0x80);
}
/******************************************************************************/
/* RingScanner: returns 1 if scanner present, else 0 */
/******************************************************************************/
static int
RingScanner (void)
{
int status;
int data;
int control;
int ret = 1;
/* save state */
data = Inb (DATA);
control = Inb (CONTROL) & 0x1F;
/* send -irq,+reset */
Outb (CONTROL, (control & 0xF) | 0x4);
/* unhandled case */
if (g674 == 1)
{
DBG (1, "OUCH! %s:%d\n", __FILE__, __LINE__);
return (0);
}
/* send ring string */
Outb (DATA, 0x22);
Outb (DATA, 0x22);
Outb (DATA, 0xAA);
Outb (DATA, 0xAA);
Outb (DATA, 0x55);
Outb (DATA, 0x55);
Outb (DATA, 0x00);
Outb (DATA, 0x00);
Outb (DATA, 0xFF);
Outb (DATA, 0xFF);
/* OK ? */
status = Inb (STATUS);
if ((status & 0xB8) != 0xB8)
{
DBG (1, "status %d doesn't match! %s:%d\n", status, __FILE__, __LINE__);
ret = 0;
}
/* if OK send 0x87 */
if (ret)
{
Outb (DATA, 0x87);
Outb (DATA, 0x87);
status = Inb (STATUS);
if ((status & 0xB8) != 0x18)
{
DBG (1, "status %d doesn't match! %s:%d\n", status, __FILE__,
__LINE__);
ret = 0;
}
}
/* if OK send 0x78 */
if (ret)
{
Outb (DATA, 0x78);
Outb (DATA, 0x78);
status = Inb (STATUS);
if ((status & 0x30) != 0x30)
{
DBG (1, "status %d doesn't match! %s:%d\n", status, __FILE__,
__LINE__);
ret = 0;
}
}
/* ring OK, send termination */
if (ret)
{
Outb (DATA, 0x08);
Outb (DATA, 0x08);
Outb (DATA, 0xFF);
Outb (DATA, 0xFF);
}
/* restore state */
Outb (CONTROL, control);
Outb (DATA, data);
return (ret);
}
/*****************************************************************************/
/* test some version : returns 1 on success, 0 otherwise */
/*****************************************************************************/
static int
TestVersion (int no)
{
int data;
int status;
int control;
int count;
int tmp;
data = Inb (DATA);
control = Inb (CONTROL) & 0x3F;
Outb (CONTROL, (control & 0x1F) | 0x04);
/* send magic sequence */
Outb (DATA, 0x22);
Outb (DATA, 0x22);
Outb (DATA, 0x22);
Outb (DATA, 0x22);
Outb (DATA, 0xAA);
Outb (DATA, 0xAA);
Outb (DATA, 0xAA);
Outb (DATA, 0xAA);
Outb (DATA, 0xAA);
Outb (DATA, 0xAA);
Outb (DATA, 0x55);
Outb (DATA, 0x55);
Outb (DATA, 0x55);
Outb (DATA, 0x55);
Outb (DATA, 0x55);
Outb (DATA, 0x55);
Outb (DATA, 0x00);
Outb (DATA, 0x00);
Outb (DATA, 0x00);
Outb (DATA, 0x00);
Outb (DATA, 0x00);
Outb (DATA, 0x00);
Outb (DATA, 0xFF);
Outb (DATA, 0xFF);
Outb (DATA, 0xFF);
Outb (DATA, 0xFF);
Outb (DATA, 0xFF);
Outb (DATA, 0xFF);
Outb (DATA, 0x87);
Outb (DATA, 0x87);
Outb (DATA, 0x87);
Outb (DATA, 0x87);
Outb (DATA, 0x87);
Outb (DATA, 0x87);
Outb (DATA, 0x78);
Outb (DATA, 0x78);
Outb (DATA, 0x78);
Outb (DATA, 0x78);
Outb (DATA, 0x78);
Outb (DATA, 0x78);
tmp = no | 0x88;
Outb (DATA, tmp);
Outb (DATA, tmp);
Outb (DATA, tmp);
Outb (DATA, tmp);
Outb (DATA, tmp);
Outb (DATA, tmp);
/* test status */
status = Inb (STATUS);
status = Inb (STATUS);
if ((status & 0xB8) != 0)
{
/* 1600P fails here */
DBG (64, "status %d doesn't match! %s:%d\n", status, __FILE__,
__LINE__);
Outb (CONTROL, control);
Outb (DATA, data);
return 0;
}
count = 0xF0;
do
{
tmp = no | 0x80;
Outb (DATA, tmp);
Outb (DATA, tmp);
Outb (DATA, tmp);
Outb (DATA, tmp);
Outb (DATA, tmp);
Outb (DATA, tmp);
tmp = no | 0x88;
Outb (DATA, tmp);
Outb (DATA, tmp);
Outb (DATA, tmp);
Outb (DATA, tmp);
Outb (DATA, tmp);
Outb (DATA, tmp);
/* command received ? */
status = Inb (STATUS);
status = ((status << 1) & 0x70) | (status & 0x80);
if (status != count)
{
/* since failure is expected, we dont't alaways print */
/* this message ... */
DBG (2, "status %d doesn't match count 0x%X! %s:%d\n", status,
count, __FILE__, __LINE__);
Outb (CONTROL, control);
Outb (DATA, data);
return (0);
}
/* next */
count -= 0x10;
}
while (count > 0);
/* restore port , successful exit */
Outb (CONTROL, control);
Outb (DATA, data);
return 1;
}
/* sends len bytes to scanner */
/* needs data channel to be set up */
/* returns 1 on success, 0 otherwise */
static int
SendLength (int *cmd, int len)
{
int i;
int reg, wait;
int try = 0;
/* send header */
retry:
wait = EPPRegisterRead (0x19) & 0xF8;
EPPRegisterWrite (0x1C, 0x55);
reg = EPPRegisterRead (0x19) & 0xF8;
EPPRegisterWrite (0x1C, 0xAA);
reg = EPPRegisterRead (0x19) & 0xF8;
/* sync when needed */
if ((wait & 0x08) == 0x00)
{
reg = EPPRegisterRead (0x1C);
while ((reg & 0x10) != 0x10)
{
DBG (0,
"SendLength failed, expected reg & 0x10=0x10 , found 0x%02X (%s:%d)\n",
reg, __FILE__, __LINE__);
if (try > 10)
{
DBG (0, "Aborting...\n");
return (0);
}
else
{
DBG (0, "Retrying ...\n");
}
/* resend */
Epilogue ();
Prologue ();
try++;
goto retry;
}
for (i = 0; i < 10; i++)
{
reg = EPPRegisterRead (0x19) & 0xF8;
if (reg != 0xC8)
{
DBG (0, "Unexpected reg19=0x%2X (%s:%d)\n", reg, __FILE__,
__LINE__);
/* 0xF0 certainly means error */
if ((reg == 0xC0) || (reg == 0xD0) || (reg == 0x80))
{
/* resend */
try++;
if (try > 20)
{
DBG (0, "SendLength retry failed (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
Epilogue ();
SendCommand (0x00);
SendCommand (0xE0);
Outb (DATA, 0x00);
Outb (CONTROL, 0x01);
Outb (CONTROL, 0x04);
SendCommand (0x30);
Prologue ();
goto retry;
}
}
}
do
{
if ((reg != 0xC0) && (reg != 0xD0) && (reg != 0xC8))
{
/* status has changed while waiting */
/* but it's too early */
DBG (0, "Unexpected reg19=0x%2X (%s:%d)\n", reg, __FILE__,
__LINE__);
}
/* 0xF0 certainly means error */
if ((reg == 0xC0) || (reg == 0xD0) || (reg == 0x80))
{
/* resend */
try++;
Epilogue ();
SendCommand (0x00);
SendCommand (0xE0);
Outb (DATA, 0x00);
Outb (CONTROL, 0x01);
Outb (CONTROL, 0x04);
SendCommand (0x30);
Prologue ();
goto retry;
}
reg = EPPRegisterRead (0x19) & 0xF8;
}
while (reg != 0xC8);
}
/* send bytes */
i = 0;
while ((reg == 0xC8) && (i < len))
{
/* write byte */
EPPRegisterWrite (0x1C, cmd[i]);
reg = EPPRegisterRead (0x19) & 0xF8;
/* 1B handling: escape it to confirm value */
if (cmd[i] == 0x1B)
{
EPPRegisterWrite (0x1C, cmd[i]);
reg = EPPRegisterRead (0x19) & 0xF8;
}
i++;
}
DBG (16, "SendLength, reg19=0x%02X (%s:%d)\n", reg, __FILE__, __LINE__);
if ((reg != 0xC0) && (reg != 0xD0))
{
DBG (0,
"SendLength failed got 0x%02X instead of 0xC0 or 0xD0 (%s:%d)\n",
reg, __FILE__, __LINE__);
DBG (0, "Blindly going on .....\n");
}
/* check if 'finished status' received too early */
if (((reg == 0xC0) || (reg == 0xD0)) && (i != len))
{
DBG (0, "SendLength failed: sent only %d bytes out of %d (%s:%d)\n", i,
len, __FILE__, __LINE__);
return (0);
}
reg = EPPRegisterRead (0x1C);
DBG (16, "SendLength, reg1C=0x%02X (%s:%d)\n", reg, __FILE__, __LINE__);
/* model 0x07 has always the last bit set to 1 */
scannerStatus = reg & 0xFC;
reg = reg & 0x10;
if (reg != 0x10)
{
DBG (0, "SendLength failed: acknowledge not received (%s:%d)\n",
__FILE__, __LINE__);
return (0);
}
if (try)
{
DBG (0, "SendLength retry success (retry %d time%s) ... (%s:%d)\n", try,
(try > 1) ? "s" : "", __FILE__, __LINE__);
}
return (1);
}
/* sends data bytes to scanner */
/* needs data channel to be set up */
/* returns 1 on success, 0 otherwise */
static int
SendData (int *cmd, int len)
{
int i;
int reg;
/* send header */
reg = EPPRegisterRead (0x19) & 0xF8;
/* send bytes */
i = 0;
while ((reg == 0xC8) && (i < len))
{
/* write byte */
EPPRegisterWrite (0x1C, cmd[i]);
reg = EPPRegisterRead (0x19) & 0xF8;
/* 1B handling: escape it to confirm value */
if (cmd[i] == 0x1B)
{
EPPRegisterWrite (0x1C, 0x1B);
reg = EPPRegisterRead (0x19) & 0xF8;
}
/* escape 55 AA pattern by adding 1B */
if ((i < len - 1) && (cmd[i] == 0x55) && (cmd[i + 1] == 0xAA))
{
EPPRegisterWrite (0x1C, 0x1B);
reg = EPPRegisterRead (0x19) & 0xF8;
}
/* next value */
i++;
}
DBG (16, "SendData, reg19=0x%02X (%s:%d)\n", reg, __FILE__, __LINE__);
if ((reg != 0xC0) && (reg != 0xD0))
{
DBG (0, "SendData failed got 0x%02X instead of 0xC0 or 0xD0 (%s:%d)\n",
reg, __FILE__, __LINE__);
DBG (0, "Blindly going on .....\n");
}
/* check if 'finished status' received too early */
if (((reg == 0xC0) || (reg == 0xD0)) && (i < len))
{
DBG (0, "SendData failed: sent only %d bytes out of %d (%s:%d)\n", i,
len, __FILE__, __LINE__);
return (0);
}
reg = EPPRegisterRead (0x1C);
DBG (16, "SendData, reg1C=0x%02X (%s:%d)\n", reg, __FILE__, __LINE__);
/* model 0x07 has always the last bit set to 1 */
scannerStatus = reg & 0xFC;
reg = reg & 0x10;
if (reg != 0x10)
{
DBG (0, "SendData failed: acknowledge not received (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
return (1);
}
/* receive data bytes from scanner */
/* needs data channel to be set up */
/* returns 1 on success, 0 otherwise */
/* uses PausedReadBuffer */
static int
PausedReadData (int size, unsigned char *dest)
{
int reg;
int tmp;
int read;
reg = EPPRegisterRead (0x19) & 0xF8;
if ((reg != 0xC0) && (reg != 0xD0))
{
DBG (0, "Unexpected reg19: 0x%02X instead of 0xC0 or 0xD0 (%s:%d)\n",
reg, __FILE__, __LINE__);
return (0);
}
EPPREGISTERREAD (0x0C, 0x04);
EPPREGISTERWRITE (0x0C, 0x44);
EPPRead32Buffer (0x0, dest);
read = PausedReadBuffer (size, dest);
if (read < size)
{
DBG (16,
"PausedReadBuffer(%d,dest) failed, only got %d bytes (%s:%d)\n",
size, read, __FILE__, __LINE__);
return (0);
}
DBG (16, "PausedReadBuffer(%d,dest) passed (%s:%d)\n", size, __FILE__,
__LINE__);
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
return (1);
}
/* receive data bytes from scanner */
/* needs data channel to be set up */
/* returns 1 on success, 0 otherwise */
static int
ReceiveData (int *cmd, int len)
{
int i;
int reg;
/* send header */
reg = EPPRegisterRead (0x19) & 0xF8;
/* send bytes */
i = 0;
while (((reg == 0xD0) || (reg == 0xC0)) && (i < len))
{
/* write byte */
cmd[i] = EPPRegisterRead (0x1C);
reg = EPPRegisterRead (0x19) & 0xF8;
i++;
}
DBG (16, "ReceiveData, reg19=0x%02X (%s:%d)\n", reg, __FILE__, __LINE__);
if ((reg != 0xC0) && (reg != 0xD0))
{
DBG (0, "SendData failed got 0x%02X instead of 0xC0 or 0xD0 (%s:%d)\n",
reg, __FILE__, __LINE__);
DBG (0, "Blindly going on .....\n");
}
/* check if 'finished status' received to early */
if (((reg == 0xC0) || (reg == 0xD0)) && (i != len))
{
DBG (0,
"ReceiveData failed: received only %d bytes out of %d (%s:%d)\n",
i, len, __FILE__, __LINE__);
return (0);
}
reg = EPPRegisterRead (0x1C);
DBG (16, "ReceiveData, reg1C=0x%02X (%s:%d)\n", reg, __FILE__, __LINE__);
/* model 0x07 has always the last bit set to 1 */
scannerStatus = reg & 0xFC;
reg = reg & 0x10;
if (reg != 0x10)
{
DBG (0, "ReceiveData failed: acknowledge not received (%s:%d)\n",
__FILE__, __LINE__);
return (0);
}
return (1);
}
/* 1=success, 0 failed */
static int
Fonc001 (void)
{
int i;
int res;
int reg;
res = 1;
while (res == 1)
{
EPPRegisterWrite (0x1A, 0x0C);
EPPRegisterWrite (0x18, 0x40);
/* send 0x06 */
EPPRegisterWrite (0x1A, 0x06);
for (i = 0; i < 10; i++)
{
reg = EPPRegisterRead (0x19) & 0xF8;
if ((reg & 0x78) == 0x38)
{
res = 0;
break;
}
}
if (res == 1)
{
EPPRegisterWrite (0x1A, 0x00);
EPPRegisterWrite (0x1A, 0x0C);
}
}
/* send 0x07 */
EPPRegisterWrite (0x1A, 0x07);
res = 1;
for (i = 0; i < 10; i++)
{
reg = EPPRegisterRead (0x19) & 0xF8;
if ((reg & 0x78) == 0x38)
{
res = 0;
break;
}
}
if (res != 0)
return (0);
/* send 0x04 */
EPPRegisterWrite (0x1A, 0x04);
res = 1;
for (i = 0; i < 10; i++)
{
reg = EPPRegisterRead (0x19) & 0xF8;
if ((reg & 0xF8) == 0xF8)
{
res = 0;
break;
}
}
if (res != 0)
return (0);
/* send 0x05 */
EPPRegisterWrite (0x1A, 0x05);
res = 1;
for (i = 0; i < 10; i++)
{
reg = EPPRegisterRead (0x1A);
if (reg == 0x05)
{
res = 0;
break;
}
}
if (res != 0)
return (0);
/* end */
EPPRegisterWrite (0x1A, 0x84);
return (1);
}
static int
InitBuffer001 (void)
{
int i, j, read, tmp, reg;
unsigned char dest[65536];
int donnees[2048];
SendWord (cmd4);
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
DBG (16, "SendWord(cmd4) passed (%s:%d) \n", __FILE__, __LINE__);
if (PausedReadData (2048, dest) == 0)
{
DBG (16, "PausedReadData(2048,dest) failed (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
DBG (16, "PausedReadData(2048,dest) passed (%s:%d)\n", __FILE__,
__LINE__);
if (SendWord (cmd1) == 0)
{
DBG (0, "SendWord(cmd1) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendWord(cmd1) passed (%s:%d)\n", __FILE__, __LINE__);
SendData (commande2,0x22);
DBG (16, "SendData(commande2,0x22) passed (%s:%d) \n", __FILE__,
__LINE__);
if (SendWord (cmd3) == 0) /* write 2048 to channel 4 */
{
DBG (0, "SendWord(cmd3) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendWord(cmd3) passed (%s:%d)\n", __FILE__, __LINE__);
/* write 2048 bytes: 4 * 512 bytes */
for (j = 0; j < 4; j++)
{
for (i = 0; i < 256; i++)
{
donnees[j * 512 + 2 * i] = i;
donnees[j * 512 + 2 * i + 1] = 0xFF - i;
}
}
if (SendData (donnees, 2048) == 0)
{
DBG (0, "SendData(donnees,%d) failed (%s:%d)\n", 2048, __FILE__,
__LINE__);
return (0);
}
TRACE (16, "SendData(donnees,2048) passed ...");
return (1); /* OK */
}
static int
InitBuffer002 (void)
{
int i, j, read, tmp, reg;
unsigned char dest[65536];
int donnees[2048];
SendWord (cmd4);
DBG (16, "SendWord(cmd4) passed (%s:%d) \n", __FILE__, __LINE__);
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
if (PausedReadData (2048, dest) == 0)
{
DBG (16, "PausedReadData(2048,dest) failed (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
DBG (16, "PausedReadData(2048,dest) passed (%s:%d)\n", __FILE__,
__LINE__);
if (SendWord (cmd1) == 0)
{
DBG (0, "SendWord(cmd1) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendWord(cmd1) passed (%s:%d)\n", __FILE__, __LINE__);
SendData (commande2,0x22);
DBG (16, "SendData(commande2) passed (%s:%d) \n", __FILE__,
__LINE__);
if (SendWord (cmd3) == 0)
{
DBG (0, "SendWord(cmd3) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendWord(cmd3) passed (%s:%d)\n", __FILE__, __LINE__);
i = 0;
while (i < 512)
{
donnees[i] = 0x00;
i++;
}
donnees[i] = 0xFF;
i++;
donnees[i] = 0xAA;
i++;
donnees[i] = 0x55;
i++;
donnees[i] = 0xFE;
i++;
for (i = 2; i < 256; i++)
{
donnees[512 + 2 * i] = i;
donnees[512 + 2 * i + 1] = 0xFF - i;
}
for (j = 0; j < 2; j++)
{
for (i = 0; i < 256; i++)
{
donnees[1024 + 512 * j + 2 * i] = i;
donnees[1024 + 512 * j + 2 * i + 1] = 0xFF - i;
}
}
if (SendData (donnees, 2048) == 0)
{
DBG (0, "SendData(donnees,%d) failed (%s:%d)\n", 2048, __FILE__,
__LINE__);
return (0);
}
TRACE (16, "SendData(donnees,2048) passed ...");
return (1);
}
/* 1 OK, 0 failed */
static int
FoncSendWord (int *cmd)
{
int reg, tmp;
Init022 ();
reg = EPPRegisterRead (0x0B);
if (reg != gEPAT)
{
/* return -1 */
DBG (0, "Error! expected reg0B=0x%02X, found 0x%02X! (%s:%d) \n", gEPAT,
reg, __FILE__, __LINE__);
return (0);
}
reg = EPPRegisterRead (0x0D);
reg = (reg & 0xE8) | 0x43;
EPPRegisterWrite (0x0D, reg);
EPPREGISTERWRITE (0x0C, 0x04);
reg = EPPRegisterRead (0x0A);
if (reg != 0x00)
{
DBG (16, "Warning! expected reg0A=0x00, found 0x%02X! (%s:%d) \n", reg,
__FILE__, __LINE__);
}
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x08, 0x21);
EPPREGISTERWRITE (0x0E, 0x0F);
EPPREGISTERWRITE (0x0F, 0x0C);
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x0E, 0x10);
EPPREGISTERWRITE (0x0F, 0x1C);
if (SendWord (cmd) == 0)
{
DBG (0, "SendWord(cmd) failed (%s:%d)\n", __FILE__, __LINE__);
}
/* termination sequence */
EPPREGISTERWRITE (0x0A, 0x00);
EPPREGISTERREAD (0x0D, 0x40);
EPPREGISTERWRITE (0x0D, 0x00);
if (GetModel () != 0x07)
SendCommand (40);
SendCommand (30);
Outb (DATA, 0x04);
tmp = Inb (CONTROL) & 0x1F;
Outb (CONTROL, tmp);
return (1);
}
/* free scanner and parallel port
0: failure
1: success
*/
int
sanei_umax_pp_ReleaseScanner (void)
{
int reg;
EPPREGISTERWRITE (0x0A, 0x00);
reg = EPPRegisterRead (0x0D);
reg = (reg & 0xBF);
EPPRegisterWrite (0x0D, reg);
if (GetModel () != 0x07)
{
if (SendCommand (0x40) == 0)
{
DBG (0, "SendCommand(0x40) (%s:%d) failed ...\n", __FILE__,
__LINE__);
return (0);
}
}
if (SendCommand (0x30) == 0)
{
DBG (0, "SendCommand(0x30) (%s:%d) failed ...\n", __FILE__, __LINE__);
return (0);
}
DBG (1, "ReleaseScanner() done ...\n");
return (1);
}
/* 1: OK
0: end session failed */
int
sanei_umax_pp_EndSession (void)
{
int tmp;
int control;
int data;
int reg;
int zero[5] = { 0, 0, 0, 0, -1 };
data = Inb (DATA);
control = Inb (CONTROL) & 0x1F;
Outb (CONTROL, control);
control = Inb (CONTROL) & 0x1F;
Outb (CONTROL, control);
g67D = 1;
if (SendCommand (0xE0) == 0)
{
DBG (0, "SendCommand(0xE0) (%s:%d) failed ...\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendCommand(0xE0) passed... (%s:%d)\n", __FILE__, __LINE__);
g6FE = 1;
g674 = 0;
ClearRegister (0);
Init001 ();
DBG (16, "Init001() passed... (%s:%d)\n", __FILE__, __LINE__);
EPPREGISTERREAD (0x0B, 0xC7);
reg = EPPRegisterRead (0x0D);
reg = (reg | 0x43);
EPPRegisterWrite (0x0D, reg);
EPPREGISTERWRITE (0x0C, 0x04);
reg = EPPRegisterRead (0x0A);
if (reg != 0x00)
{
if (reg != 0x1C)
DBG (0, "Expected 0x00 found 0x%02X .... (%s:%d)\n", reg, __FILE__,
__LINE__);
else
{
DBG (16, "Previous probe detected .... (%s:%d)\n", __FILE__,
__LINE__);
}
}
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x08, 0x21);
EPPREGISTERWRITE (0x0E, 0x0F);
EPPREGISTERWRITE (0x0F, 0x0C);
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x0E, 0x10);
EPPREGISTERWRITE (0x0F, 0x1C);
if (SendWord (zero) == 0)
{
DBG (16, "SendWord(zero) failed (%s:%d)\n", __FILE__, __LINE__);
}
Epilogue ();
sanei_umax_pp_CmdSync (0xC2);
sanei_umax_pp_CmdSync (0x00); /* cancels any pending operation */
sanei_umax_pp_CmdSync (0x00); /* cancels any pending operation */
sanei_umax_pp_ReleaseScanner ();
/* restore port state */
Outb (DATA, 0x04);
Outb (CONTROL, gControl);
/* OUF */
DBG (1, "End session done ...\n");
return (1);
}
/* 1: OK
2: homing happened
3: scanner busy
0: init failed
init transport layer
init scanner
*/
int
sanei_umax_pp_InitScanner (int recover)
{
int i, j;
int status;
int readcmd[64];
int sentcmd[64];
/* in umax1220u, this buffer is opc[16] */
j = 0;
sentcmd[j] = 0x02;
j++;
sentcmd[j] = 0x80;
j++;
sentcmd[j] = 0x00;
j++;
sentcmd[j] = 0x70;
j++;
sentcmd[j] = 0x00;
j++;
sentcmd[j] = 0x00;
j++;
sentcmd[j] = 0x00;
j++;
sentcmd[j] = 0x2F;
j++;
sentcmd[j] = 0x2F;
j++;
sentcmd[j] = 0x07;
j++;
sentcmd[j] = 0x00;
j++;
sentcmd[j] = 0x00;
j++;
sentcmd[j] = 0x00;
j++;
sentcmd[j] = 0x80;
j++;
sentcmd[j] = 0xF0;
j++; /* F0 means light on, 90 light off */
if (GetModel () == 0x07)
{
sentcmd[j] = 0x00;
j++;
}
else
{
sentcmd[j] = 0x18;
j++;
}
sentcmd[j] = -1;
/* fails here if there is an unfinished previous scan */
if (CmdSetGet (0x02, j, sentcmd) != 1)
{
DBG (0, "CmdSetGet(0x02,j,sentcmd) failed (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
DBG (16, "CmdSetGet(0x02,j,sentcmd) passed ... (%s:%d)\n", __FILE__,
__LINE__);
/* needs some init */
if (sentcmd[15] == 0x18)
{
sentcmd[15] = 0x00; /* was 0x18 */
if (CmdSetGet (0x02, j, sentcmd) != 1)
{
DBG (0, "CmdSetGet(0x02,j,sentcmd) failed (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
DBG (16, "CmdSetGet(0x02,j,sentcmd) passed ... (%s:%d)\n", __FILE__,
__LINE__);
/* in umax1220u, this buffer does not exist */
j = 0;
sentcmd[j] = 0xA0;
j++;
sentcmd[j] = 0xA1;
j++;
sentcmd[j] = 0xA2;
j++;
sentcmd[j] = 0xA3;
j++;
sentcmd[j] = 0xA4;
j++;
sentcmd[j] = 0xA5;
j++;
sentcmd[j] = 0xA6;
j++;
sentcmd[j] = 0xA7;
j++;
sentcmd[j] = -1;
if (CmdSetGet (0x01, j, sentcmd) != 1)
{
DBG (0, "CmdSetGet(0x02,j,sentcmd) failed (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
DBG (16, "CmdSetGet(0x01,j,sentcmd) passed ... (%s:%d)\n", __FILE__,
__LINE__);
}
/* ~ opb3: inquire status */
if (CmdGet (0x08, 36, readcmd) == 0)
{
DBG (0, "CmdGet(0x08,36,readcmd) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
if (DBG_LEVEL >= 32)
{
Bloc8Decode (readcmd);
}
DBG (16, "CmdGet(0x08,36,readcmd) passed (%s:%d)\n", __FILE__, __LINE__);
/* is the scanner busy parking ? */
status = sanei_umax_pp_ScannerStatus ();
DBG (8, "INQUIRE SCANNER STATUS IS 0x%02X (%s:%d)\n", status, __FILE__,
__LINE__);
if ((!recover) && (status & MOTOR_BIT) == 0x00)
{
DBG (1, "Warning: scanner motor on, giving up ... (%s:%d)\n", __FILE__,
__LINE__);
return (3);
}
/* head homing needed ? */
if ((readcmd[34] != 0x1A) || (recover == 1))
{ /* homing needed, readcmd[34] should be 0x48 */
int op01[17] =
{ 0x01, 0x00, 0x32, 0x70, 0x00, 0x00, 0x60, 0x2F, 0x17, 0x05, 0x00,
0x00, 0x00, 0x80, 0xE4, 0x00, -1
};
int op05[17] =
{ 0x01, 0x00, 0x01, 0x70, 0x00, 0x00, 0x60, 0x2F, 0x13, 0x05, 0x00,
0x00, 0x00, 0x80, 0xF0, 0x00, -1
};
int op02[37] =
{ 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x00, 0x04, 0x40,
0x01, 0x00, 0x20, 0x02, 0x00, 0x16, 0x00, 0x70, 0x9F, 0x06, 0x00,
0x00, 0xF6, 0x4D, 0xA0, 0x00, 0x8B, 0x49, 0x2A, 0xE9, 0x68, 0xDF,
0x0B, 0x1A, 0x00, -1
};
int op04[37] =
{ 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x00, 0x03, 0xC1,
0x80, 0x00, 0x20, 0x02, 0x00, 0x16, 0x80, 0x15, 0x78, 0x03, 0x03,
0x00, 0x00, 0x46, 0xA0, 0x00, 0x8B, 0x49, 0x2A, 0xE9, 0x68, 0xDF,
0x0B, 0x1A, 0x00, -1
};
int op03[9] = { 0x00, 0x00, 0x00, 0xAA, 0xCC, 0xEE, 0xFF, 0xFF, -1 };
CMDSYNC (0xC2);
CMDSETGET (0x02, 16, op01);
CMDSETGET (0x08, 36, op02);
if (!recover)
{
CMDSYNC (0xC2);
CMDSYNC (0x00);
CMDSETGET (0x04, 8, op03);
CMDSYNC (0x40);
do
{
sleep (1);
CMDSYNC (0xC2);
}
while ((sanei_umax_pp_ScannerStatus () & 0x90) != 0x90);
op01[2] = 0x1E;
op01[9] = 0x01;
CMDSETGET (0x02, 16, op01);
CMDSETGET (0x08, 36, op02);
CMDSYNC (0x00);
CMDSYNC (0x00);
CMDSETGET (0x04, 8, op03);
CMDSYNC (0x40);
do
{
sleep (1);
CMDSYNC (0xC2);
}
while ((sanei_umax_pp_ScannerStatus () & 0x90) != 0x90);
CMDSYNC (0x00);
}
for (i = 0; i < 4; i++)
{
do
{
usleep (500000);
CMDSYNC (0xC2);
status = sanei_umax_pp_ScannerStatus ();
status = status & 0x10;
}
while (status != 0x10); /* was 0x90 */
CMDSETGET (0x02, 16, op05);
CMDSETGET (0x08, 36, op04);
CMDSYNC (0x40);
status = sanei_umax_pp_ScannerStatus ();
DBG (16, "loop %d passed, status=0x%02X (%s:%d)\n", i, status,
__FILE__, __LINE__);
}
/* get head back home ... */
do
{
i++;
do
{
usleep (500000);
CMDSYNC (0xC2);
status = sanei_umax_pp_ScannerStatus ();
status = status & 0x10;
}
while (status != 0x10); /* was 0x90 */
CMDSETGET (0x02, 16, op05);
CMDSETGET (0x08, 36, op04);
CMDSYNC (0x40);
status = sanei_umax_pp_ScannerStatus ();
DBG (16, "loop %d passed, status=0x%02X (%s:%d)\n", i, status,
__FILE__, __LINE__);
}
while ((status & MOTOR_BIT) == 0x00); /* 0xD0 when head is back home */
do
{
usleep (500000);
CMDSYNC (0xC2);
}
while ((sanei_umax_pp_ScannerStatus () & 0x90) != 0x90);
/* don't do automatic home sequence on recovery */
if (!recover)
{
CMDSYNC (0x00);
op01[2] = 0x1A;
op01[3] = 0x74; /* was 0x70 */
op01[9] = 0x05; /* initial value */
op01[14] = 0xF4; /* was 0xE4 */
CMDSETGET (0x02, 16, op01);
CMDSETGET (0x08, 36, op02);
CMDSYNC (0xC2);
CMDSYNC (0x00);
CMDSETGET (0x04, 8, op03);
CMDSYNC (0x40);
/* wait for automatic homing sequence */
/* to complete, thus avoiding */
/* scanning too early */
do
{
/* the sleep is here to prevent */
/* excessive CPU usage, can be */
/* removed, if we don't care */
sleep (3);
CMDSYNC (0xC2);
DBG (16, "PARKING polling status is 0x%02X (%s:%d)\n",
sanei_umax_pp_ScannerStatus (), __FILE__, __LINE__);
}
while (sanei_umax_pp_ScannerStatus () == 0x90);
}
/* signal homing */
return (2);
}
/* end ... */
DBG (1, "Scanner init done ...\n");
return (1);
}
/*
1: OK
2: failed, try again
0: init failed
initialize the transport layer
*/
static int
InitTransport610P (int recover)
{
int control;
int data;
int zero[5] = { 0, 0, 0, 0, -1 };
/* recover is not used yet, but will */
recover = 0; /* quit compiler quiet .. */
/* set port state */
data = Inb (DATA);
control = Inb (CONTROL) & 0x0C;
Outb (CONTROL, control);
control = Inb (CONTROL) & 0x0C;
Outb (CONTROL, control);
gControl = 0x0C;
g67D = 1;
if (SendCommand (0xE0) == 0)
{
DBG (0, "SendCommand(0xE0) (%s:%d) failed ...\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendCommand(0xE0) passed...\n");
g6FE = 1;
ClearRegister (0);
DBG (16, "ClearRegister(0) passed...\n");
/* sync */
Prologue ();
if (SendWord (zero) == 0)
{
DBG (0, "SendWord(zero) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendWord(zero) passed (%s:%d)\n", __FILE__, __LINE__);
Epilogue ();
/* OK ! */
DBG (1, "InitTransport610P done ...\n");
return (1);
}
/*
1: OK
2: failed, try again
0: init failed
initialize the transport layer
*/
static int
InitTransport1220P (int recover)
{
int i, j;
int control;
int data;
int reg;
unsigned char *dest = NULL;
int zero[5] = { 0, 0, 0, 0, -1 };
int model;
/* init cancel handling */
/* InitCancel(); */
/* recover is not used yet, but will */
recover = 0; /* quit compiler quiet .. */
/* set port state */
data = Inb (DATA);
control = Inb (CONTROL) & 0x0C;
Outb (CONTROL, control);
control = Inb (CONTROL) & 0x0C;
Outb (CONTROL, control);
gControl = 0x0C;
g67D = 1;
if (SendCommand (0xE0) == 0)
{
DBG (0, "SendCommand(0xE0) (%s:%d) failed ...\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendCommand(0xE0) passed...\n");
g6FE = 1;
ClearRegister (0);
DBG (16, "ClearRegister(0) passed...\n");
Init001 ();
DBG (16, "Init001() passed... (%s:%d)\n", __FILE__, __LINE__);
gEPAT = 0xC7;
reg = EPPRegisterRead (0x0B);
if (reg != gEPAT)
{
DBG (16, "Error! expected reg0B=0x%02X, found 0x%02X! (%s:%d) \n",
gEPAT, reg, __FILE__, __LINE__);
DBG (16, "Scanner needs probing ... \n");
sanei_umax_pp_ReleaseScanner ();
if (sanei_umax_pp_ProbeScanner (recover) != 1)
{
return (0);
}
else
{
sanei_umax_pp_ReleaseScanner ();
return (2); /* signals retry InitTransport() */
}
}
reg = EPPRegisterRead (0x0D);
reg = (reg & 0xE8) | 0x43;
EPPRegisterWrite (0x0D, reg);
EPPREGISTERWRITE (0x0C, 0x04);
reg = EPPRegisterRead (0x0A);
if (reg != 0x00)
{
if (reg != 0x1C)
{
DBG (0, "Warning! expected reg0A=0x00, found 0x%02X! (%s:%d) \n",
reg, __FILE__, __LINE__);
}
else
{
DBG (16, "Scanner in idle state .... (%s:%d)\n", __FILE__,
__LINE__);
}
}
/* model detection: redone since we might not be probing each time ... */
/* write addr in 0x0E, read value at 0x0F */
EPPREGISTERWRITE (0x0E, 0x01);
model = EPPRegisterRead (0x0F);
SetModel (model);
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x08, 0x21);
EPPREGISTERWRITE (0x0E, 0x0F);
EPPREGISTERWRITE (0x0F, 0x0C);
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x0E, 0x10);
EPPREGISTERWRITE (0x0F, 0x1C);
EPPREGISTERWRITE (0x0A, 0x11);
dest = (unsigned char *) (malloc (65536));
if (dest == NULL)
{
DBG (0, "Failed to allocate 64 Ko !\n");
return (0);
}
for (i = 0; i < 256; i++)
{
dest[i * 2] = i;
dest[i * 2 + 1] = 0xFF - i;
dest[512 + i * 2] = i;
dest[512 + i * 2 + 1] = 0xFF - i;
}
for (i = 0; i < 150; i++)
{
if (GetEPPMode () == 32)
{
EPPWrite32Buffer (0x400, dest);
DBG (16,
"Loop %d: EPPWrite32Buffer(0x400,dest) passed... (%s:%d)\n", i,
__FILE__, __LINE__);
}
else
{
EPPWriteBuffer (0x400, dest);
DBG (16, "Loop %d: EPPWriteBuffer(0x400,dest) passed... (%s:%d)\n",
i, __FILE__, __LINE__);
}
}
EPPREGISTERWRITE (0x0A, 0x18);
EPPREGISTERWRITE (0x0A, 0x11);
for (i = 0; i < 150; i++)
{
if (GetEPPMode () == 32)
{
EPPRead32Buffer (0x400, dest);
}
else
{
EPPReadBuffer (0x400, dest);
}
for (j = 0; j < 256; j++)
{
if (dest[j * 2] != j)
{
DBG (0,
"Altered buffer value at %03X, expected %02X, found %02X\n",
j * 2, j, dest[j * 2]);
return (0);
}
if (dest[j * 2 + 1] != 0xFF - j)
{
DBG
(0,
"Altered buffer value at %03X, expected %02X, found %02X\n",
j * 2 + 1, 0xFF - j, dest[j * 2 + 1]);
return (0);
}
if (dest[512 + j * 2] != j)
{
DBG (0,
"Altered buffer value at %03X, expected %02X, found %02X\n",
512 + j * 2, j, dest[512 + j * 2]);
return (0);
}
if (dest[512 + j * 2 + 1] != 0xFF - j)
{
DBG
(0,
"Altered buffer value at %03X, expected 0x%02X, found 0x%02X\n",
512 + j * 2 + 1, 0xFF - j, dest[512 + j * 2 + 1]);
return (0);
}
}
if (GetEPPMode () == 32)
DBG (16, "Loop %d: EPPRead32Buffer(0x400,dest) passed... (%s:%d)\n",
i, __FILE__, __LINE__);
else
DBG (16, "Loop %d: EPPReadBuffer(0x400,dest) passed... (%s:%d)\n", i,
__FILE__, __LINE__);
}
EPPREGISTERWRITE (0x0A, 0x18);
if (Fonc001 () != 1)
{
DBG (0, "Fonc001() failed ! (%s:%d) \n", __FILE__, __LINE__);
return (0);
}
DBG (16, "Fonc001() passed ... (%s:%d) \n", __FILE__, __LINE__);
/* sync */
if (SendWord (zero) == 0)
{
DBG (0, "SendWord(zero) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendWord(zero) passed (%s:%d)\n", __FILE__, __LINE__);
Epilogue ();
/* OK ! */
free (dest);
DBG (1, "InitTransport1220P done ...\n");
return (1);
}
/*
1: OK
2: failed, try again
0: init failed
initialize the transport layer
*/
int
sanei_umax_pp_InitTransport (int recover)
{
switch (sanei_umax_pp_getastra ())
{
case 610:
return (InitTransport610P (recover));
case 1220:
case 1600:
case 2000:
return (InitTransport1220P (recover));
}
return (0);
}
/*
* returns 1 if testing OK
* 0 if it fails
* send value if value != 0
*/
static int
Test610P (int value)
{
int data, control, val;
/* save state */
data = Inb (DATA);
control = Inb (CONTROL) & 0x1F;
Outb (CONTROL, control);
Outb (DATA, 0x22);
usleep (10000);
Outb (DATA, 0x22);
usleep (10000);
Outb (DATA, 0x22);
usleep (10000);
Outb (DATA, 0x22);
usleep (10000);
Outb (DATA, 0x22);
usleep (10000);
Outb (DATA, 0x22);
usleep (10000);
Outb (DATA, 0x22);
usleep (10000);
Outb (DATA, 0x22);
usleep (10000);
Outb (DATA, 0xAA);
usleep (10000);
Outb (DATA, 0xAA);
usleep (10000);
Outb (DATA, 0xAA);
usleep (10000);
Outb (DATA, 0xAA);
usleep (10000);
Outb (DATA, 0xAA);
usleep (10000);
Outb (DATA, 0xAA);
usleep (10000);
Outb (DATA, 0xAA);
usleep (10000);
Outb (DATA, 0xAA);
usleep (10000);
Outb (DATA, 0x55);
usleep (10000);
Outb (DATA, 0x55);
usleep (10000);
Outb (DATA, 0x55);
usleep (10000);
Outb (DATA, 0x55);
usleep (10000);
Outb (DATA, 0x55);
usleep (10000);
Outb (DATA, 0x55);
usleep (10000);
Outb (DATA, 0x55);
usleep (10000);
Outb (DATA, 0x55);
usleep (10000);
Outb (DATA, 0x00);
usleep (10000);
Outb (DATA, 0x00);
usleep (10000);
Outb (DATA, 0x00);
usleep (10000);
Outb (DATA, 0x00);
usleep (10000);
Outb (DATA, 0x00);
usleep (10000);
Outb (DATA, 0x00);
usleep (10000);
Outb (DATA, 0x00);
usleep (10000);
Outb (DATA, 0x00);
usleep (10000);
Outb (DATA, 0xFF);
usleep (10000);
Outb (DATA, 0xFF);
usleep (10000);
Outb (DATA, 0xFF);
usleep (10000);
Outb (DATA, 0xFF);
usleep (10000);
Outb (DATA, 0xFF);
usleep (10000);
Outb (DATA, 0xFF);
usleep (10000);
Outb (DATA, 0xFF);
usleep (10000);
Outb (DATA, 0xFF);
usleep (10000);
if (value)
{
Outb (DATA, value);
usleep (10000);
Outb (DATA, value);
usleep (10000);
Outb (DATA, value);
usleep (10000);
Outb (DATA, value);
usleep (10000);
Outb (DATA, value);
usleep (10000);
Outb (DATA, value);
usleep (10000);
Outb (DATA, value);
usleep (10000);
Outb (DATA, value);
usleep (10000);
}
val = Inb (STATUS);
usleep (10000);
Outb (DATA, data);
Outb (CONTROL, control);
return (1);
}
/*
* returns 1 if testing OK
* 0 if it fails
*/
static int
In256 (void)
{
int val, i, tmp;
Outb (CONTROL, 0x04);
usleep (10000);
Outb (CONTROL, 0x0C);
usleep (10000);
val = Inb (STATUS);
Outb (CONTROL, 0x0E);
usleep (10000);
Outb (CONTROL, 0x0E);
usleep (10000);
Outb (CONTROL, 0x0E);
usleep (10000);
tmp = val;
i = 0;
while ((tmp == val) && (i < 256))
{
tmp = Inb (STATUS);
usleep (10000);
i++;
}
if (tmp != val)
{
DBG (1, "Error, expected status 0x%02X, got 0x%02X (%s:%d)\n", val, tmp,
__FILE__, __LINE__);
return (0);
}
Outb (CONTROL, 0x04);
usleep (10000);
Outb (CONTROL, 0x04);
usleep (10000);
return (1);
}
/* 1: OK
0: probe failed */
static int
Probe610P (int recover)
{
int tmp, i;
/*int zero[5] = { 0, 0, 0, 0, -1 }; to be used */
/* recover is not used yet, but will */
recover = 0; /* quit compiler quiet .. */
/* make sure we won't try 1220/200P later */
sanei_umax_pp_setastra (610);
if (!Test610P (0x87))
{
DBG (1, "Ring610P(0x87) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
else
{
DBG (16, "Ring610P(0x87) passed...\n");
}
if (!In256 ())
{
DBG (1, "In256() failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
else
{
DBG (16, "In256() passed...\n");
}
/* test PS2 mode */
tmp = SlowNibbleRegisterRead (0x0B);
if (tmp != 0x88)
{ /* tmp = 0x88 for 610P */
DBG (1, "Found 0x%X expected 0x88 (%s:%d)\n", tmp, __FILE__, __LINE__);
}
/* clear register 3 */
ClearRegister (3);
DBG (16, "ClearRegister(3) passed...\n");
/* wait ? */
i = 65535;
while (i > 0)
{
tmp = Inb (DATA);
tmp = Inb (DATA);
i--;
}
DBG (16, "FFFF in loop passed...\n");
ClearRegister (0);
DBG (16, "ClearRegister(0) passed... (%s:%d)\n", __FILE__, __LINE__);
fflush (stdout);
/* no EPP32 for 610P */
SetEPPMode (8);
/* XXX STEF XXX : insert init trans + re homing */
/* successfull end ... */
DBG (1, "UMAX Astra 610P detected\n");
DBG (1, "Probe610P done ...\n");
return (1);
}
/* 1: OK
0: probe failed */
int
sanei_umax_pp_ProbeScanner (int recover)
{
int tmp, i, j, k;
int reg;
int read;
unsigned char *dest = NULL;
int donnees[2049];
int val;
int zero[5] = { 0, 0, 0, 0, -1 };
int model;
/* save and set CONTROL */
tmp = (Inb (CONTROL)) & 0x1F;
tmp = (Inb (CONTROL)) & 0x1F;
Outb (CONTROL, tmp);
Outb (CONTROL, tmp);
tmp = Inb (DATA);
tmp = Inb (CONTROL) & 0x3F;
Outb (CONTROL, tmp);
tmp = Inb (CONTROL) & 0x3F;
tmp = Inb (DATA);
tmp = Inb (CONTROL) & 0x3F;
tmp = Inb (DATA);
/* any scanner ? */
tmp = RingScanner ();
if (tmp)
{
i = 0;
while ((i < 50) && (tmp))
{
tmp = RingScanner ();
i++;
}
}
if (!tmp)
{
DBG (1, "No 1220P/2000P scanner detected by 'RingScanner()'...\n");
DBG (1, "Trying 610P...\n");
return (Probe610P (recover));
}
DBG (16, "RingScanner passed...\n");
gControl = Inb (CONTROL) & 0x3F;
g67D = 1;
if (SendCommand (0x30) == 0)
{
DBG (0, "SendCommand(0x30) (%s:%d) failed ...\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendCommand(0x30) passed ... (%s:%d)\n", __FILE__, __LINE__);
g67E = 4; /* bytes to read */
if (SendCommand (0x00) == 0)
{
DBG (0, "SendCommand(0x00) (%s:%d) failed ...\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendCommand(0x00) passed... (%s:%d)\n", __FILE__, __LINE__);
g67E = 0; /* bytes to read */
if (TestVersion (0) == 0)
{
DBG (0, "TestVersion(0) (%s:%d) failed ...\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "TestVersion(0) passed...\n");
/* must fail for 1220P and 2000P */
if (TestVersion (1) == 0) /* software doesn't do it for model 0x07 */
{ /* but it works .. */
DBG (16, "TestVersion(1) failed (expected) ... (%s:%d)\n", __FILE__,
__LINE__);
}
else
{
DBG (0, "Unexpected success on TestVersion(1) ... (%s:%d)\n", __FILE__,
__LINE__);
}
if (TestVersion (0) == 0)
{
DBG (0, "TestVersion(0) (%s:%d) failed ...\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "TestVersion(0) passed...\n");
/* must fail */
if (TestVersion (1) == 0)
{
DBG (16, "TestVersion(1) failed (expected) ... (%s:%d)\n", __FILE__,
__LINE__);
}
else
{
DBG (0, "Unexpected success on TestVersion(1) ... (%s:%d)\n", __FILE__,
__LINE__);
}
Outb (DATA, 0x04);
Outb (CONTROL, 0x0C);
Outb (DATA, 0x04);
Outb (CONTROL, 0x0C);
gControl = Inb (CONTROL) & 0x3F;
Outb (CONTROL, gControl & 0xEF);
if (SendCommand (0x40) == 0)
{
DBG (0, "SendCommand(0x40) (%s:%d) failed ...\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendCommand(0x40) passed...\n");
if (SendCommand (0xE0) == 0)
{
DBG (0, "SendCommand(0xE0) (%s:%d) failed ...\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendCommand(0xE0) passed...\n");
ClearRegister (0);
DBG (16, "ClearRegister(0) passed...\n");
SPPResetLPT ();
DBG (16, "SPPResetLPT() passed...\n");
Outb (CONTROL, 4);
Outb (CONTROL, 4);
/* test PS2 mode */
tmp = SlowNibbleRegisterRead (0x0B);
if (tmp == 0xC7)
{
/* epat C7 detected */
DBG (16, "SlowNibbleRegisterRead(0x0B)=0x%X passed...\n", tmp);
WriteSlow (8, 0);
DBG (16, "WriteSlow(8,0) passed... (%s:%d)\n", __FILE__, __LINE__);
tmp = SlowNibbleRegisterRead (0x0A);
if (tmp != 0x00)
{
if (tmp == 0x1C)
{
DBG (16, "Previous probe detected ... (%s:%d)\n", __FILE__,
__LINE__);
}
else
{
DBG (0, "Found 0x%X expected 0x00 (%s:%d)\n", tmp, __FILE__,
__LINE__);
}
}
DBG (16, "SlowNibbleRegisterRead(0x0A)=0x%X passed ...(%s:%d)\n", tmp,
__FILE__, __LINE__);
}
else
{
DBG (0, "Found 0x%X expected 0xC7 or 0x88 (%s:%d)\n", tmp, __FILE__,
__LINE__);
return 0;
}
/* clear register 3 */
ClearRegister (3);
DBG (16, "ClearRegister(3) passed...\n");
/* wait ? */
i = 65535;
while (i > 0)
{
tmp = Inb (DATA);
tmp = Inb (DATA);
i--;
}
DBG (16, "FFFF in loop passed...\n");
ClearRegister (0);
DBG (16, "ClearRegister(0) passed... (%s:%d)\n", __FILE__, __LINE__);
fflush (stdout);
/* 1220/2000P branch */
WRITESLOW (0x0E, 1);
/* register 0x0F used only once: model number ? Or ASIC revision ? */
/* comm mode ? */
model = SlowNibbleRegisterRead (0x0F);
DBG (1, "UMAX Astra 1220/1600/2000 P ASIC detected (mode=%d)\n", model);
SetModel (model);
DBG (16, "SlowNibbleRegisterRead(0x0F) passed... (%s:%d)\n", __FILE__,
__LINE__);
/* scanner powered off */
if (model == 0x1B)
{
DBG (0, "Register 0x0F=0x1B, scanner powered off ! (%s:%d)\n", __FILE__,
__LINE__);
return 0;
}
if ((model != 0x1F) && (model != 0x07))
{
DBG
(0,
"Unexpected value for for register 0x0F, expected 0x07 or 0x1F, got 0x%02X ! (%s:%d)\n",
model, __FILE__, __LINE__);
DBG (0, "There is a new scanner revision in town, or a bug ....\n");
}
WRITESLOW (0x08, 0x02);
WRITESLOW (0x0E, 0x0F);
WRITESLOW (0x0F, 0x0C);
WRITESLOW (0x0C, 0x04);
tmp = SlowNibbleRegisterRead (0x0D);
if ((tmp != 0x00) && (tmp != 0x40))
{
DBG
(0,
"Unexpected value for for register 0x0D, expected 0x00 or 0x40, got 0x%02X ! (%s:%d)\n",
tmp, __FILE__, __LINE__);
}
WRITESLOW (0x0D, 0x1B);
switch (model)
{
case 0x1F:
WRITESLOW (0x12, 0x14);
SLOWNIBBLEREGISTEREAD (0x12, 0x10);
break;
case 0x07:
WRITESLOW (0x12, 0x00);
SLOWNIBBLEREGISTEREAD (0x12, 0x00); /* we may get 0x20 */
/* must depend on the parport */
/* model 0x07 + 0x00=>0x20=2000P */
break;
default:
WRITESLOW (0x12, 0x00);
SLOWNIBBLEREGISTEREAD (0x12, 0x20);
break;
}
SLOWNIBBLEREGISTEREAD (0x0D, 0x18);
SLOWNIBBLEREGISTEREAD (0x0C, 0x04);
SLOWNIBBLEREGISTEREAD (0x0A, 0x00);
WRITESLOW (0x0E, 0x0A);
WRITESLOW (0x0F, 0x00);
WRITESLOW (0x0E, 0x0D);
WRITESLOW (0x0F, 0x00);
/* write/read full buffer */
for (i = 0; i < 256; i++)
{
WRITESLOW (0x0A, i);
SLOWNIBBLEREGISTEREAD (0x0A, i);
WRITESLOW (0x0A, 0xFF - i);
SLOWNIBBLEREGISTEREAD (0x0A, 0xFF - i);
}
/* end test for nibble byte/byte mode */
/* now we try nibble buffered mode */
WRITESLOW (0x13, 0x01);
WRITESLOW (0x13, 0x00); /*reset something */
WRITESLOW (0x0A, 0x11);
/* read buffer */
dest = (unsigned char *) (malloc (65536));
for (i = 0; i < 10; i++) /* 10 ~ 11 ? */
{
NibbleReadBuffer (0x400, dest);
DBG (16, "Loop %d: NibbleReadBuffer passed ... (%s:%d)\n", i, __FILE__,
__LINE__);
}
/* write buffer */
for (i = 0; i < 10; i++)
{
WriteBuffer (0x400, dest);
DBG (16, "Loop %d: WriteBuffer passed ... (%s:%d)\n", i, __FILE__,
__LINE__);
}
SLOWNIBBLEREGISTEREAD (0x0C, 0x04);
WRITESLOW (0x13, 0x01);
WRITESLOW (0x13, 0x00);
WRITESLOW (0x0A, 0x18);
Outb (CONTROL, 4);
SLOWNIBBLEREGISTEREAD (0x0A, 0x18);
WRITESLOW (0x08, 0x40);
WRITESLOW (0x08, 0x60);
WRITESLOW (0x08, 0x22);
/* test EPP MODE */
SetEPPMode (8);
ClearRegister (0);
DBG (16, "ClearRegister(0) passed... (%s:%d)\n", __FILE__, __LINE__);
WRITESLOW (0x08, 0x22);
Init001 ();
DBG (16, "Init001() passed... (%s:%d)\n", __FILE__, __LINE__);
gEPAT = 0xC7;
Init002 (0);
DBG (16, "Init002(0) passed... (%s:%d)\n", __FILE__, __LINE__);
for (i = 0; i < 256; i++)
{
EPPREGISTERWRITE (0x0A, i);
EPPREGISTERREAD (0x0A, i);
EPPREGISTERWRITE (0x0A, 0xFF - i);
EPPREGISTERREAD (0x0A, 0xFF - i);
}
EPPREGISTERWRITE (0x13, 0x01);
EPPREGISTERWRITE (0x13, 0x00);
EPPREGISTERWRITE (0x0A, 0x11);
for (i = 0; i < 10; i++)
{
EPPReadBuffer (0x400, dest);
for (j = 0; j < 512; j++)
{
if (dest[2 * j] != (j % 256))
{
DBG (0, "Loop %d, char %d EPPReadBuffer failed! (%s:%d)\n", i,
j * 2, __FILE__, __LINE__);
return (0);
}
if (dest[2 * j + 1] != (0xFF - (j % 256)))
{
DBG (0, "Loop %d, char %d EPPReadBuffer failed! (%s:%d)\n", i,
j * 2 + 1, __FILE__, __LINE__);
return (0);
}
}
DBG (16, "Loop %d: EPPReadBuffer(0x400,dest) passed... (%s:%d)\n", i,
__FILE__, __LINE__);
}
for (i = 0; i < 10; i++)
{
EPPWriteBuffer (0x400, dest);
DBG (16, "Loop %d: EPPWriteBuffer(0x400,dest) passed... (%s:%d)\n", i,
__FILE__, __LINE__);
}
EPPREGISTERREAD (0x0C, 4);
EPPREGISTERWRITE (0x13, 0x01);
EPPREGISTERWRITE (0x13, 0x00);
EPPREGISTERWRITE (0x0A, 0x18);
Outb (DATA, 0x0);
ClearRegister (0);
Init001 ();
Init004 ();
DBG (16, "Init004() passed... (%s:%d)\n", __FILE__, __LINE__);
tmp = Inb (CONTROL) & 0x1F;
Outb (CONTROL, tmp);
Outb (CONTROL, tmp);
WRITESLOW (0x68, 0x21);
Init001 ();
DBG (16, "Init001() passed... (%s:%d)\n", __FILE__, __LINE__);
WRITESLOW (0x68, 0x21);
Init001 ();
DBG (16, "Init001() passed... (%s:%d)\n", __FILE__, __LINE__);
SPPResetLPT ();
if (Init005 (0x80))
{
DBG (0, "Init005(0x80) failed... (%s:%d)\n", __FILE__, __LINE__);
}
DBG (16, "Init005(0x80) passed... (%s:%d)\n", __FILE__, __LINE__);
if (Init005 (0xEC))
{
DBG (0, "Init005(0xEC) failed... (%s:%d)\n", __FILE__, __LINE__);
}
DBG (16, "Init005(0xEC) passed... (%s:%d)\n", __FILE__, __LINE__);
/* write/read buffer loop */
for (i = 0; i < 256; i++)
{
EPPREGISTERWRITE (0x0A, i);
EPPREGISTERREAD (0x0A, i);
EPPREGISTERWRITE (0x0A, 0xFF - i);
EPPREGISTERREAD (0x0A, 0xFF - i);
}
DBG (16, "EPP write/read buffer loop passed... (%s:%d)\n", __FILE__,
__LINE__);
EPPREGISTERWRITE (0x13, 0x01);
EPPREGISTERWRITE (0x13, 0x00);
EPPREGISTERWRITE (0x0A, 0x11);
/* test EPP32 mode */
/* we set 32 bits I/O mode first, then step back to */
/* 8bits if tests fail */
SetEPPMode (32);
for (i = 0; i < 10; i++)
{
EPPRead32Buffer (0x400, dest);
/* if 32 bit I/O work, we should have a buffer */
/* filled by 00 FF 01 FE 02 FD 03 FC ..... */
for (j = 0; j < 0x200; j++)
{
if ((dest[j * 2] != j % 256)
|| (dest[j * 2 + 1] != 0xFF - (j % 256)))
{
DBG (1, "Setting EPP I/O to 8 bits ... (%s:%d)\n", __FILE__,
__LINE__);
SetEPPMode (8);
}
}
DBG (16, "Loop %d: EPPRead32Buffer(0x400) passed... (%s:%d)\n", i,
__FILE__, __LINE__);
}
DBG (1, "%d bits EPP data transfer\n", GetEPPMode ());
for (i = 0; i < 10; i++)
{
EPPWrite32Buffer (0x400, dest);
DBG (16, "Loop %d: EPPWrite32Buffer(0x400,dest) passed... (%s:%d)\n", i,
__FILE__, __LINE__);
}
EPPREGISTERREAD (0x0C, 0x04);
EPPREGISTERWRITE (0x13, 0x01);
EPPREGISTERWRITE (0x13, 0x00);
EPPREGISTERWRITE (0x0A, 0x18);
WRITESLOW (0x68, 0x21);
Init001 ();
DBG (16, "Init001() passed... (%s:%d)\n", __FILE__, __LINE__);
SPPResetLPT ();
if (Init005 (0x80))
{
DBG (0, "Init005(0x80) failed... (%s:%d)\n", __FILE__, __LINE__);
}
DBG (16, "Init005(0x80) passed... (%s:%d)\n", __FILE__, __LINE__);
if (Init005 (0xEC))
{
DBG (0, "Init005(0xEC) failed... (%s:%d)\n", __FILE__, __LINE__);
}
DBG (16, "Init005(0xEC) passed... (%s:%d)\n", __FILE__, __LINE__);
/* write/read buffer loop */
for (i = 0; i < 256; i++)
{
EPPREGISTERWRITE (0x0A, i);
EPPREGISTERREAD (0x0A, i);
EPPREGISTERWRITE (0x0A, 0xFF - i);
EPPREGISTERREAD (0x0A, 0xFF - i);
}
DBG (16, "EPP write/read buffer loop passed... (%s:%d)\n", __FILE__,
__LINE__);
EPPREGISTERWRITE (0x13, 0x01);
EPPREGISTERWRITE (0x13, 0x00);
EPPREGISTERWRITE (0x0A, 0x11);
for (i = 0; i < 10; i++)
{
EPPRead32Buffer (0x400, dest);
DBG (16, "Loop %d: EPPRead32Buffer(0x400) passed... (%s:%d)\n", i,
__FILE__, __LINE__);
}
for (i = 0; i < 10; i++)
{
EPPWrite32Buffer (0x400, dest);
DBG (16, "Loop %d: EPPWrite32Buffer(0x400,dest) passed... (%s:%d)\n", i,
__FILE__, __LINE__);
}
EPPREGISTERREAD (0x0C, 0x04);
EPPREGISTERWRITE (0x13, 0x01);
EPPREGISTERWRITE (0x13, 0x00);
EPPREGISTERWRITE (0x0A, 0x18);
WRITESLOW (0x68, 0x21);
g6FE = 1;
Init001 ();
DBG (16, "Init001() passed... (%s:%d)\n", __FILE__, __LINE__);
reg = EPPRegisterRead (0x0D);
reg = (reg & 0xE8) | 0x43;
EPPRegisterWrite (0x0D, reg);
EPPREGISTERWRITE (0x0A, 0x18);
EPPREGISTERWRITE (0x0E, 0x0F);
EPPREGISTERWRITE (0x0F, 0x0C);
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x0E, 0x10);
EPPREGISTERWRITE (0x0F, 0x1C);
reg = EPPRegisterRead (0x0D);
reg = EPPRegisterRead (0x0D);
reg = EPPRegisterRead (0x0D);
reg = (reg & 0xB7) | 0x03;
EPPRegisterWrite (0x0D, reg);
DBG (16, "(%s:%d) passed \n", __FILE__, __LINE__);
reg = EPPRegisterRead (0x12); /* 0x10 for model 0x0F, 0x20 for model 0x07 */
reg = reg & 0xEF;
EPPRegisterWrite (0x12, reg);
DBG (16, "(%s:%d) passed \n", __FILE__, __LINE__);
reg = EPPRegisterRead (0x0A);
if (reg != 0x1C)
{
DBG (0, "Warning! expected reg0A=0x1C, found 0x%02X! (%s:%d) \n", reg,
__FILE__, __LINE__);
}
DBG (16, "(%s:%d) passed \n", __FILE__, __LINE__);
Init021 ();
DBG (16, "Init021() passed... (%s:%d)\n", __FILE__, __LINE__);
/* some sort of countdown, some warming-up ? */
/* maybe some pauses are needed */
/* if (model == 0x07) */
{
EPPREGISTERWRITE (0x0A, 0x00);
reg = EPPRegisterRead (0x0D);
reg = (reg & 0xE8);
EPPRegisterWrite (0x0D, reg);
DBG (16, "(%s:%d) passed \n", __FILE__, __LINE__);
Init022 ();
DBG (16, "Init022() passed... (%s:%d)\n", __FILE__, __LINE__);
reg = EPPRegisterRead (0x0B);
if (reg != gEPAT)
{
DBG (0, "Error! expected reg0B=0x%02X, found 0x%02X! (%s:%d) \n",
gEPAT, reg, __FILE__, __LINE__);
return (0);
}
reg = EPPRegisterRead (0x0D);
reg = (reg & 0xE8) | 0x43;
EPPRegisterWrite (0x0D, reg);
EPPREGISTERWRITE (0x0C, 0x04);
reg = EPPRegisterRead (0x0A);
if (reg != 0x00)
{
DBG (0, "Warning! expected reg0A=0x00, found 0x%02X! (%s:%d) \n",
reg, __FILE__, __LINE__);
}
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x08, 0x21);
EPPREGISTERWRITE (0x0E, 0x0F);
EPPREGISTERWRITE (0x0F, 0x0C);
usleep (10000);
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x0E, 0x10);
EPPREGISTERWRITE (0x0F, 0x1C);
reg = EPPRegisterRead (0x13);
if (reg != 0x00)
{
DBG (0, "Warning! expected reg13=0x00, found 0x%02X! (%s:%d) \n",
reg, __FILE__, __LINE__);
}
EPPREGISTERWRITE (0x13, 0x81);
usleep (10000);
EPPREGISTERWRITE (0x13, 0x80);
EPPREGISTERWRITE (0x0E, 0x04);
EPPREGISTERWRITE (0x0F, 0xFF);
EPPREGISTERWRITE (0x0E, 0x05);
EPPREGISTERWRITE (0x0F, 0x03);
EPPREGISTERWRITE (0x10, 0x66);
usleep (10000);
EPPREGISTERWRITE (0x0E, 0x04);
EPPREGISTERWRITE (0x0F, 0xFF);
EPPREGISTERWRITE (0x0E, 0x05);
EPPREGISTERWRITE (0x0F, 0x01);
EPPREGISTERWRITE (0x10, 0x55);
usleep (10000);
EPPREGISTERWRITE (0x0E, 0x04);
EPPREGISTERWRITE (0x0F, 0xFF);
EPPREGISTERWRITE (0x0E, 0x05);
EPPREGISTERWRITE (0x0F, 0x00);
EPPREGISTERWRITE (0x10, 0x44);
usleep (10000);
EPPREGISTERWRITE (0x0E, 0x04);
EPPREGISTERWRITE (0x0F, 0x7F);
EPPREGISTERWRITE (0x0E, 0x05);
EPPREGISTERWRITE (0x0F, 0x00);
EPPREGISTERWRITE (0x10, 0x33);
usleep (10000);
EPPREGISTERWRITE (0x0E, 0x04);
EPPREGISTERWRITE (0x0F, 0x3F);
EPPREGISTERWRITE (0x0E, 0x05);
EPPREGISTERWRITE (0x0F, 0x00);
EPPREGISTERWRITE (0x10, 0x22);
usleep (10000);
EPPREGISTERWRITE (0x0E, 0x04);
EPPREGISTERWRITE (0x0F, 0x00);
EPPREGISTERWRITE (0x0E, 0x05);
EPPREGISTERWRITE (0x0F, 0x00);
EPPREGISTERWRITE (0x10, 0x11);
usleep (10000);
EPPREGISTERWRITE (0x13, 0x81);
usleep (10000);
EPPREGISTERWRITE (0x13, 0x80);
EPPREGISTERWRITE (0x0E, 0x04);
EPPREGISTERWRITE (0x0F, 0x00);
EPPREGISTERWRITE (0x0E, 0x05);
EPPREGISTERWRITE (0x0F, 0x00);
usleep (10000);
reg = EPPRegisterRead (0x10);
DBG (1,"Count-down value is 0x%02X (%s:%d)\n", reg,__FILE__, __LINE__);
/* 2 reports of CF, was FF first (typo ?) */
/* CF seems a valid value */
/* in case of CF, we may have timeout ... */
/*if (reg != 0x00)
{
DBG (0, "Warning! expected reg10=0x00, found 0x%02X! (%s:%d) \n",
reg, __FILE__, __LINE__);
}*/
EPPREGISTERWRITE (0x13, 0x00);
}
EPPREGISTERWRITE (0x0A, 0x00);
reg = EPPRegisterRead (0x0D);
reg = (reg & 0xE8);
EPPRegisterWrite (0x0D, reg);
DBG (16, "(%s:%d) passed \n", __FILE__, __LINE__);
Init022 ();
DBG (16, "Init022() passed... (%s:%d)\n", __FILE__, __LINE__);
reg = EPPRegisterRead (0x0B);
if (reg != gEPAT)
{
DBG (0, "Error! expected reg0B=0x%02X, found 0x%02X! (%s:%d) \n", gEPAT,
reg, __FILE__, __LINE__);
return (0);
}
reg = EPPRegisterRead (0x0D);
reg = (reg & 0xE8) | 0x43;
EPPRegisterWrite (0x0D, reg);
EPPREGISTERWRITE (0x0C, 0x04);
reg = EPPRegisterRead (0x0A);
if (reg != 0x00)
{
DBG (0, "Warning! expected reg0A=0x00, found 0x%02X! (%s:%d) \n", reg,
__FILE__, __LINE__);
}
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x08, 0x21);
EPPREGISTERWRITE (0x0E, 0x0F);
EPPREGISTERWRITE (0x0F, 0x0C);
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x0E, 0x10);
EPPREGISTERWRITE (0x0F, 0x1C);
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
EPPREGISTERWRITE (0x0A, 0x1C);
/* real start of high level protocol ? */
if (Fonc001 () != 1)
{
DBG (0, "Fonc001() failed ! (%s:%d) \n", __FILE__, __LINE__);
return (0);
}
DBG (16, "Fct001() passed (%s:%d) \n", __FILE__, __LINE__);
reg = EPPRegisterRead (0x19) & 0xC8;
/* if reg=E8 or D8 , we have a 'messed' scanner */
for(k=0;k<1;k++)
{
/* is SendLength 34 bytes */
SendWord(cmd1);
DBG (16, "SendWord(cmd1) passed (%s:%d) \n", __FILE__,
__LINE__);
/* SendData */
SendData (commande2,0x22);
DBG (16, "SendData(commande2) passed (%s:%d) \n", __FILE__,
__LINE__);
/* is SendLength 2048 bytes */
SendWord (cmd3);
DBG (16, "SendWord(cmd3) passed (%s:%d) \n", __FILE__,
__LINE__);
/* fill buffer ? */
memset (donnees, 0x00, 2048 * sizeof (int));
donnees[512] = 0xFF;
donnees[513] = 0xAA;
donnees[514] = 0x55;
if (SendData (donnees, 2048) == 0)
{
DBG (0, "SendData(donnees,%d) failed (%s:%d)\n", 2048, __FILE__,
__LINE__);
return (0);
}
TRACE (16, "SendData(donnees,2048) passed ...");
SendWord(cmd4);
DBG (16, "SendWord(cmd4) passed (%s:%d) \n", __FILE__,
__LINE__);
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
reg = EPPRegisterRead (0x19) & 0xF8;
if ((reg != 0xD0) && (reg != 0xC0))
{
DBG (0, "Expected reg19=0xD0 or 0xC0, got 0x%02X! (%s:%d)\n", reg,
__FILE__, __LINE__);
DBG (0, "Going on .....\n");
}
EPPREGISTERREAD (0x0C, 0x04);
EPPREGISTERWRITE (0x0C, 0x44);
EPPRead32Buffer (0x0, dest);
read = PausedReadBuffer (2048, dest);
DBG (16, "PausedReadBuffer(2048,dest)=%d passed (%s:%d)\n", read, __FILE__,
__LINE__);
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
/* dest should hold the same datas than donnees */
for (i = 0; i < 2047; i++)
{
if (donnees[i] != (int) (dest[i]))
{
DBG
(0,
"Warning data read back differs: expected %02X found dest[%d]=%02X ! (%s:%d)\n",
donnees[i], i, dest[i], __FILE__, __LINE__);
}
}
if (SendWord (cmd1) == 0)
{
DBG (0, "SendWord(cmd1) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendWord(cmd1) passed (%s:%d)\n", __FILE__, __LINE__);
SendData (commande2,0x22);
DBG (16, "SendData(commande2) passed (%s:%d) \n", __FILE__,
__LINE__);
if (SendWord (cmd3) == 0)
{
DBG (0, "SendWord(cmd3) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendWord(cmd3) passed (%s:%d)\n", __FILE__, __LINE__);
/* send buffer 2048 bytes wide */
for (j = 0; j < 4; j++)
{
for (i = 0; i < 256; i++)
{
donnees[512 * j + 2 * i] = i;
donnees[512 * j + 2 * i] = 0xFF - i;
}
}
if (SendData (donnees, 2048) == 0)
{
DBG (0, "SendData(donnees,%d) failed (%s:%d)\n", 2048, __FILE__,
__LINE__);
return (0);
}
TRACE (16, "SendData(donnees,2048) passed ...");
SendWord (cmd4);
DBG (16, "SendWord(cmd4) passed (%s:%d) \n", __FILE__, __LINE__);
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
if (PausedReadData (2048, dest) == 0)
{
DBG (16, "PausedReadData(2048,dest) failed (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
DBG (16, "PausedReadData(2048,dest) passed (%s:%d)\n", __FILE__,
__LINE__);
}
if (SendWord (cmd1) == 0)
{
DBG (0, "SendWord(cmd1) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendWord(cmd1) passed (%s:%d)\n", __FILE__, __LINE__);
SendData (commande2,0x22);
DBG (16, "SendData(commande2) passed (%s:%d) \n", __FILE__,
__LINE__);
if (SendWord (cmd3) == 0)
{
DBG (0, "SendWord(cmd3) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendWord(cmd3) passed (%s:%d)\n", __FILE__, __LINE__);
i = 0;
while (i < 512)
{
donnees[i] = 0x00;
i++;
}
donnees[i] = 0xFF;
i++;
donnees[i] = 0xAA;
i++;
donnees[i] = 0x55;
i++;
donnees[i] = 0xFE;
i++;
for (i = 2; i < 256; i++)
{
donnees[512 + 2 * i] = i;
donnees[512 + 2 * i + 1] = 0xFF - i;
}
for (j = 0; j < 2; j++)
{
for (i = 0; i < 256; i++)
{
donnees[1024 + 512 * j + 2 * i] = i;
donnees[1024 + 512 * j + 2 * i + 1] = 0xFF - i;
}
}
if (SendData (donnees, 2048) == 0)
{
DBG (0, "SendData(donnees,%d) failed (%s:%d)\n", 2048, __FILE__,
__LINE__);
return (0);
}
TRACE (16, "SendData(donnees,2048) passed ...");
if (InitBuffer001 () != 1)
{
DBG (0, "InitBuffer001 failed! (%s:%d) \n", __FILE__, __LINE__);
return (0);
}
DBG (16, "InitBuffer001 passed ... (%s:%d) \n", __FILE__, __LINE__);
DBG (16, "InitBuffer002+InitBuffer001 loop %d passed ... (%s:%d) \n", j,
__FILE__, __LINE__);
/* we are still connected to EPAT */
for (j = 0; j < 2; j++)
{
if (InitBuffer002 () != 1)
{
DBG (0, "InitBuffer002 failed! (%s:%d) \n", __FILE__, __LINE__);
return (0);
}
DBG (16, "InitBuffer002 passed ... (%s:%d) \n", __FILE__, __LINE__);
if (InitBuffer001 () != 1)
{
DBG (0, "InitBuffer001 failed! (%s:%d) \n", __FILE__, __LINE__);
return (0);
}
DBG (16, "InitBuffer001 passed ... (%s:%d) \n", __FILE__, __LINE__);
DBG (16, "InitBuffer002+InitBuffer001 loop %d passed ... (%s:%d) \n", j,
__FILE__, __LINE__);
}
/* we re read the buffer to ensure it has been correctly loaded */
if (SendWord (cmd4) == 0)
{
DBG (0, "SendWord(cmd4) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "SendWord(cmd4) passed (%s:%d)\n", __FILE__, __LINE__);
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
if (PausedReadData (2048, dest) == 0)
{
DBG (16, "PausedReadData(2048,dest) failed (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
DBG (16, "PausedReadData(2048,dest) passed (%s:%d)\n", __FILE__,
__LINE__);
EPPREGISTERWRITE (0x1A, 0x00);
EPPREGISTERWRITE (0x1A, 0x0C);
EPPREGISTERWRITE (0x1A, 0x00);
EPPREGISTERWRITE (0x1A, 0x0C);
EPPREGISTERWRITE (0x0A, 0x11);
for (i = 0; i < 150; i++)
{
EPPWrite32Buffer (0x400, dest);
DBG (16, "Loop %d: EPPWrite32Buffer(0x400,dest) passed... (%s:%d)\n", i,
__FILE__, __LINE__);
}
EPPREGISTERWRITE (0x0A, 0x18);
EPPREGISTERWRITE (0x0A, 0x11); /*start transfert */
for (i = 0; i < 150; i++)
{
EPPRead32Buffer (0x400, dest);
DBG (16, "Loop %d: EPPRead32Buffer(0x400,dest) passed... (%s:%d)\n", i,
__FILE__, __LINE__);
}
/* this bloc is almost CmdSync(0x0) */
EPPREGISTERWRITE (0x0A, 0x18); /*end transfer */
if (Fonc001 () != 1)
{
DBG (0, "Fonc001() failed ! (%s:%d) \n", __FILE__, __LINE__);
return (0);
}
DBG (16, "Fct001() passed (%s:%d) \n", __FILE__, __LINE__);
if (SendWord (zero) == 0)
{
DBG (0, "SendWord(zero) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
Epilogue ();
DBG (16, "SendWord(zero) passed (%s:%d)\n", __FILE__, __LINE__);
/* end transport init */
/* now high level protocol begins */
val = sanei_umax_pp_InitScanner (recover);
if (val == 0)
{
DBG (0, "InitScanner() failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
/* if no homing .... */
if (val == 1)
{
CMDSYNC (0);
CMDSYNC (0xC2);
CMDSYNC (0);
}
/* set port to its initial state */
Outb (DATA, 0x04);
Outb (CONTROL, 0x0C);
free (dest);
DBG (1, "Probe done ...\n");
return (1);
}
/* signal handler: simply flags the cancel request */
/*static void
handler (int signum)
{*/
/* reserve SIGUSR1 for futur use */
/*if (signum != SIGUSR1)
gCancel = 1;
} */
/* set the signal handler to manage signals */
/*static int
InitCancel (void)
{
signal (SIGINT, handler);
signal (SIGTERM, handler);
return (1);
}*/
/* cancel sequence */
/* no free, no fclose ... emergency exit */
/*static int
Cancel (void)
{
if (sanei_umax_pp_Park () == 0)
{
DBG (0, "Park failed !!! (%s:%d)\n", __FILE__, __LINE__);
}
sanei_umax_pp_EndSession ();
DBG (1, "Cancel done ...\n");
}*/
static int
deconnect_epat (void)
{
int tmp;
EPPREGISTERWRITE (0x0A, 0x00);
EPPREGISTERREAD (0x0D, 0x40);
EPPREGISTERWRITE (0x0D, 0x00);
if (GetModel () != 0x07)
SendCommand (40);
SendCommand (30);
Outb (DATA, gData);
Outb (CONTROL, gControl);
return (1);
}
static int
connect_epat (void)
{
int reg;
gData = Inb (DATA);
gControl = Inb (CONTROL) & 0x1F;
Outb (CONTROL, gControl);
gControl = Inb (CONTROL) & 0x1F;
Outb (CONTROL, gControl);
if (SendCommand (0xE0) != 1)
{
DBG (0, "connect_epat: SendCommand(0xE0) failed! (%s:%d)\n", __FILE__,
__LINE__);
/* we try to clean all */
Epilogue ();
return (0);
}
Outb (DATA, 0x00);
Outb (CONTROL, 0x01);
Outb (CONTROL, 0x04);
ClearRegister (0);
Init001 ();
reg = EPPRegisterRead (0x0B);
if (reg != gEPAT)
{
/* ASIC version is not */
/* the one expected (epat c7) */
DBG (0, "Error! expected reg0B=0x%02X, found 0x%02X! (%s:%d) \n", gEPAT,
reg, __FILE__, __LINE__);
/* we try to clean all */
Epilogue ();
return (0);
}
reg = EPPRegisterRead (0x0D);
reg = (reg | 0x43) & 0xEB;
EPPRegisterWrite (0x0D, reg);
EPPREGISTERWRITE (0x0C, 0x04);
reg = EPPRegisterRead (0x0A);
if (reg != 0x00)
{
/* a previous unfinished command */
/* has left an uncleared value */
DBG (0, "Warning! expected reg0A=0x00, found 0x%02X! (%s:%d) \n", reg,
__FILE__, __LINE__);
}
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x08, 0x21);
EPPREGISTERWRITE (0x0E, 0x0F);
EPPREGISTERWRITE (0x0F, 0x0C);
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x0E, 0x10);
EPPREGISTERWRITE (0x0F, 0x1C);
return (1);
}
static int
connect_610P (void)
{
int tmp;
gData = Inb (DATA);
Outb (DATA, 0xAA);
Outb (CONTROL, 0x0E);
Inb (CONTROL);
Inb (CONTROL);
Outb (DATA, 0x00);
Outb (CONTROL, 0x0C);
Inb (CONTROL);
Inb (CONTROL);
Outb (DATA, 0x55);
Outb (CONTROL, 0x0E);
Inb (CONTROL);
Inb (CONTROL);
Outb (DATA, 0xFF);
Outb (CONTROL, 0x0C);
Inb (CONTROL);
Inb (CONTROL);
Outb (CONTROL, 0x04);
Inb (CONTROL);
Inb (CONTROL);
Outb (DATA, 0x40);
Outb (CONTROL, 0x06);
tmp = Inb (STATUS);
if (tmp != 0x38)
{
DBG (0, "Error! expected STATUS=0x38, found 0x%02X! (%s:%d) \n", tmp,
__FILE__, __LINE__);
return (0);
}
Outb (CONTROL, 0x07);
tmp = Inb (STATUS);
if (tmp != 0x38)
{
DBG (0, "Error! expected STATUS=0x38, found 0x%02X! (%s:%d) \n", tmp,
__FILE__, __LINE__);
return (0);
}
Outb (CONTROL, 0x04);
tmp = Inb (STATUS);
if (tmp != 0xF8)
{
DBG (0, "Error! expected STATUS=0xF8, found 0x%02X! (%s:%d) \n", tmp,
__FILE__, __LINE__);
return (0);
}
return (1);
}
static int
deconnect_610P (void)
{
int tmp, i;
Outb (CONTROL, 0x04);
i = 0;
do
{
i++;
tmp = Inb (CONTROL);
if (tmp != 0x04)
{
DBG (0, "Error! expected CONTROL=0x04, found 0x%02X! (%s:%d) \n",
tmp, __FILE__, __LINE__);
return (0);
}
}
while ((i < 41) && (tmp == 0x04));
Outb (DATA, gData);
return (1);
}
static int
Prologue (void)
{
switch (sanei_umax_pp_getastra ())
{
case 610:
return (connect_610P ());
case 1220:
case 1600:
case 2000:
return (connect_epat ());
}
return (0);
}
static int
Epilogue (void)
{
switch (sanei_umax_pp_getastra ())
{
case 610:
return (deconnect_610P ());
case 1220:
case 1600:
case 2000:
return (deconnect_epat ());
}
return (0);
}
static int
CmdSet (int cmd, int len, int *val)
{
int word[5];
int i;
/* cmd 08 as 2 length depending upon model */
if ((cmd == 8) && (GetModel () == 0x07))
{
len = 35;
}
/* compute word */
word[0] = len / 65536;
word[1] = len / 256 % 256;
word[2] = len % 256;
word[3] = (cmd & 0x3F) | 0x80;
if (!Prologue ())
{
DBG (0, "CmdSet: Prologue failed ! (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
/* send data */
if (SendLength (word, 4) == 0)
{
DBG (0, "SendLength(word,4) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
TRACE (16, "SendLength(word,4) passed ...");
/* head end */
Epilogue ();
if (len > 0)
{
/* send body */
if (!Prologue ())
{
DBG (0, "CmdSet: Prologue failed ! (%s:%d)\n", __FILE__,
__LINE__);
}
if (DBG_LEVEL >= 8)
{
char *str = NULL;
str = malloc (3 * len);
if (str != NULL)
{
for (i = 0; i < len; i++)
{
sprintf (str + 3 * i, "%02X ", val[i]);
}
str[3 * i] = 0x00;
DBG (8, "String sent for %02X: %s\n", cmd, str);
free (str);
}
else
{
TRACE (8, "not enough memory for debugging ...");
}
}
/* send data */
if (SendData (val, len) == 0)
{
DBG (0, "SendData(word,%d) failed (%s:%d)\n", len, __FILE__,
__LINE__);
Epilogue ();
return (0);
}
TRACE (16, "SendData(val,len) passed ...");
/* body end */
Epilogue ();
}
return (1);
}
static int
CmdGet (int cmd, int len, int *val)
{
int word[5];
int i;
/* cmd 08 as 2 length depending upon model */
if ((cmd == 8) && (GetModel () == 0x07))
{
len = 35;
}
/* compute word */
word[0] = len / 65536;
word[1] = len / 256 % 256;
word[2] = len % 256;
word[3] = (cmd & 0x3F) | 0x80 | 0x40; /* 0x40 means 'read' */
word[4] = -1;
/* send header */
if (!Prologue ())
{
DBG (0, "CmdGet: Prologue failed ! (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
/* send data */
if (SendLength (word, 4) == 0)
{
DBG (0, "SendLength(word,4) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
TRACE (16, "SendLength(word,4) passed ...");
/* head end */
Epilogue ();
/* send header */
if (!Prologue ())
{
DBG (0, "CmdGet: Prologue failed ! (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
/* get actual data */
if (ReceiveData (val, len) == 0)
{
DBG (0, "ReceiveData(val,len) failed (%s:%d)\n", __FILE__, __LINE__);
Epilogue ();
return (0);
}
if (DBG_LEVEL >= 8)
{
char *str = NULL;
str = malloc (3 * len);
if (str != NULL)
{
for (i = 0; i < len; i++)
{
sprintf (str + 3 * i, "%02X ", val[i]);
}
str[3 * i] = 0x00;
DBG (8, "String received for %02X: %s\n", cmd, str);
free (str);
}
else
{
TRACE (8, "not enough memory for debugging ...");
}
}
Epilogue ();
return (1);
}
static int
CmdSetGet (int cmd, int len, int *val)
{
int *tampon;
int i;
/* model revision 0x07 uses 35 bytes buffers */
/* cmd 08 as 2 length depending upon model */
if ((cmd == 8) && (GetModel () == 0x07))
{
len = 35;
}
/* first we send */
if (CmdSet (cmd, len, val) == 0)
{
DBG (0, "CmdSetGet failed ! (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
tampon = (int *) malloc (len * sizeof (int));
memset (tampon, 0x00, len * sizeof (int));
if (tampon == NULL)
{
DBG (0, "Failed to allocate room for %d int ! (%s:%d)\n", len, __FILE__,
__LINE__);
Epilogue ();
return (0);
}
/* then we receive */
if (CmdGet (cmd, len, tampon) == 0)
{
DBG (0, "CmdSetGet failed ! (%s:%d)\n", __FILE__, __LINE__);
free (tampon);
Epilogue ();
return (0);
}
/* check and copy */
for (i = 0; (i < len) && (val[i] >= 0); i++)
{
if (tampon[i] != val[i])
{
DBG
(0,
"Warning data read back differs: expected %02X found tampon[%d]=%02X ! (%s:%d)\n",
val[i], i, tampon[i], __FILE__, __LINE__);
}
val[i] = tampon[i];
}
/* OK */
free (tampon);
return (1);
}
/* 1 OK, 0 failed */
static int
CmdGetBuffer (int cmd, int len, unsigned char *buffer)
{
int reg, tmp, i;
int word[5], read;
int needed;
/* compute word */
word[0] = len / 65536;
word[1] = len / 256 % 256;
word[2] = len % 256;
word[3] = (cmd & 0x3F) | 0x80 | 0x40;
word[4] = -1;
/* send word: len+addr(?) */
if (FoncSendWord (word) == 0)
{
DBG (0, "FoncSendWord(word) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
DBG (16, "(%s:%d) passed \n", __FILE__, __LINE__);
Init022 ();
DBG (16, "Init022() passed... (%s:%d)\n", __FILE__, __LINE__);
reg = EPPRegisterRead (0x0B);
if (reg != gEPAT)
{
/* return -1 */
DBG (0, "Error! expected reg0B=0x%02X, found 0x%02X! (%s:%d) \n", gEPAT,
reg, __FILE__, __LINE__);
return (0);
}
reg = EPPRegisterRead (0x0D);
reg = (reg & 0xE8) | 0x43;
EPPRegisterWrite (0x0D, reg);
EPPREGISTERWRITE (0x0C, 0x04);
reg = EPPRegisterRead (0x0A);
if (reg != 0x00)
{
DBG (0, "Warning! expected reg0A=0x00, found 0x%02X! (%s:%d) \n", reg,
__FILE__, __LINE__);
}
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x08, 0x21);
EPPREGISTERWRITE (0x0E, 0x0F);
EPPREGISTERWRITE (0x0F, 0x0C);
EPPREGISTERWRITE (0x0A, 0x1C);
EPPREGISTERWRITE (0x0E, 0x10);
EPPREGISTERWRITE (0x0F, 0x1C);
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
i = 0;
reg = EPPRegisterRead (0x19) & 0xF8;
/* wait if busy */
while ((reg & 0x08) == 0x08)
reg = EPPRegisterRead (0x19) & 0xF8;
if ((reg != 0xC0) && (reg != 0xD0))
{
DBG (0, "CmdGetBuffer failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
read = 0;
reg = EPPRegisterRead (0x0C);
if (reg != 0x04)
{
DBG (0, "CmdGetBuffer failed: unexpected status 0x%02X ...(%s:%d)\n",
reg, __FILE__, __LINE__);
return (0);
}
EPPREGISTERWRITE (0x0C, reg | 0x40);
/* actual data */
read = 0;
while (read < len)
{
needed = len - read;
if (needed > 32768)
needed = 32768;
InitPausedRead ();
tmp = PausedReadBuffer (needed, buffer + read);
if (tmp < needed)
{
DBG (64, "CmdGetBuffer only got %d bytes out of %d ...(%s:%d)\n",
tmp, needed, __FILE__, __LINE__);
}
else
{
DBG (64,
"CmdGetBuffer got all %d bytes out of %d , read=%d...(%s:%d)\n",
tmp, 32768, read, __FILE__, __LINE__);
}
read += tmp;
DBG (16, "Read %d bytes out of %d (last block is %d bytes) (%s:%d)\n",
read, len, tmp, __FILE__, __LINE__);
if (read < len)
{
/* wait for scanner to be ready */
reg = EPPRegisterRead (0x19) & 0xF8;
DBG (64, "Status after block read is 0x%02X (%s:%d)\n", reg,
__FILE__, __LINE__);
if ((reg & 0x08) == 0x08)
{
int pass = 0;
do
{
reg = EPPRegisterRead (0x19) & 0xF8;
usleep (100);
pass++;
}
while ((pass < 32768) && ((reg & 0x08) == 0x08));
DBG (64, "Status after waiting is 0x%02X (pass=%d) (%s:%d)\n",
reg, pass, __FILE__, __LINE__);
if ((reg != 0xC0) && (reg != 0xD0))
{
DBG (0,
"Unexpected status 0x%02X, expected 0xC0 or 0xD0 ! (%s:%d)\n",
reg, __FILE__, __LINE__);
DBG (0, "Going on...\n");
}
}
/* signal we want next data chunk */
reg = EPPRegisterRead (0x0C);
EPPRegisterWrite (0x0C, reg | 0x40);
}
}
/* OK ! */
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
/* epilogue */
Epilogue ();
return (1);
}
/* 1 OK, 0 failed */
static int
CmdGetBuffer32 (int cmd, int len, unsigned char *buffer)
{
int reg, tmp, i;
int word[5], read;
/* compute word */
word[0] = len / 65536;
word[1] = len / 256 % 256;
word[2] = len % 256;
word[3] = (cmd & 0x3F) | 0x80 | 0x40;
if (!Prologue ())
{
DBG (0, "CmdSet: Prologue failed ! (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
/* send data */
if (SendLength (word, 4) == 0)
{
DBG (0, "SendLength(word,4) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
TRACE (16, "SendLength(word,4) passed ...");
/* head end */
Epilogue ();
Prologue ();
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
i = 0;
reg = EPPRegisterRead (0x19) & 0xF8;
/* wait if busy */
while ((reg & 0x08) == 0x08)
reg = EPPRegisterRead (0x19) & 0xF8;
if ((reg != 0xC0) && (reg != 0xD0))
{
DBG (0, "CmdGetBuffer32 failed: unexpected status 0x%02X ...(%s:%d)\n",
reg, __FILE__, __LINE__);
return (0);
}
reg = EPPRegisterRead (0x0C);
if (reg != 0x04)
{
DBG (0, "CmdGetBuffer32 failed: unexpected status 0x%02X ...(%s:%d)\n",
reg, __FILE__, __LINE__);
return (0);
}
EPPREGISTERWRITE (0x0C, reg | 0x40);
read = 0;
while (read < len)
{
if (read + 1700 < len)
{
tmp = 1700;
EPPRead32Buffer (tmp, buffer + read);
reg = EPPRegisterRead (0x19) & 0xF8;
if ((read + tmp < len) && (reg & 0x08) == 0x08)
{
do
{
reg = EPPRegisterRead (0x19) & 0xF8;
}
while ((reg & 0x08) == 0x08);
if ((reg != 0xC0) && (reg != 0xD0))
{
DBG (0,
"Unexpected status 0x%02X, expected 0xC0 or 0xD0 ! (%s:%d)\n",
reg, __FILE__, __LINE__);
DBG (0, "Going on...\n");
}
}
reg = EPPRegisterRead (0x0C);
EPPRegisterWrite (0x0C, reg | 0x40);
read += tmp;
}
else
{
tmp = len - read;
EPPRead32Buffer (tmp, buffer + read);
read += tmp;
if ((read < len))
{
reg = EPPRegisterRead (0x19) & 0xF8;
while ((reg & 0x08) == 0x08)
{
reg = EPPRegisterRead (0x19) & 0xF8;
}
}
}
}
/* OK ! */
Epilogue ();
return (1);
}
int
sanei_umax_pp_CmdSync (int cmd)
{
int word[5];
if (!Prologue ())
{
DBG (0, "CmdSync: Prologue failed ! (%s:%d)\n", __FILE__, __LINE__);
}
/* compute word */
word[0] = 0x00;
word[1] = 0x00;
word[2] = 0x00;
word[3] = cmd;
/* send data */
if (SendLength (word, 4) == 0)
{
DBG (0, "SendLength(word,4) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
TRACE (16, "SendLength(word,4) passed ...");
/* end OK */
Epilogue ();
return (1);
}
/* numbers of bytes read, else 0 (failed) */
/* read data by chunk EXACTLY the width of the scan area in the given */
/* resolution . If a valid file descriptor is given, we write data */
/* in it according to the color mode, before polling the scanner */
/* len should not be bigger than 2 Megs */
int
CmdGetBlockBuffer (int cmd, int len, int window, unsigned char *buffer)
{
struct timeval td, tf;
float elapsed;
int reg, i;
int word[5], read;
/* compute word */
word[0] = len / 65536;
word[1] = len / 256 % 256;
word[2] = len % 256;
word[3] = (cmd & 0x3F) | 0x80 | 0x40;
if (!Prologue ())
{
DBG (0, "CmdGetBlockBuffer: Prologue failed ! (%s:%d)\n", __FILE__,
__LINE__);
}
/* send data */
if (SendLength (word, 4) == 0)
{
DBG (0, "SendLength(word,4) failed (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
TRACE (16, "SendLength(word,4) passed ...");
/* head end */
Epilogue ();
if (!Prologue ())
{
DBG (0, "CmdGetBlockBuffer: Prologue failed ! (%s:%d)\n", __FILE__,
__LINE__);
}
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
i = 0;
/* init counter */
read = 0;
/* read scanner state */
reg = EPPRegisterRead (0x19) & 0xF8;
/* read loop */
while (read < len)
{
/* wait for the data to be ready */
gettimeofday (&td, NULL);
while ((reg & 0x08) == 0x08)
{
reg = EPPRegisterRead (0x19) & 0xF8;
gettimeofday (&tf, NULL);
elapsed =
((tf.tv_sec * 1000000 + tf.tv_usec) -
(td.tv_sec * 1000000 + td.tv_usec)) / 1000000;
if (elapsed > 3)
{
DBG
(0,
"Time-out (%.2f s) waiting for scanner ... giving up on status 0x%02X ! (%s:%d)\n",
elapsed, reg, __FILE__, __LINE__);
Epilogue ();
return (read);
}
}
if ((reg != 0xC0) && (reg != 0xD0) && (reg != 0x00))
{
DBG (0,
"Unexpected status 0x%02X, expected 0xC0 or 0xD0 ! (%s:%d)\n",
reg, __FILE__, __LINE__);
DBG (0, "Going on...\n");
}
/* signals next chunk */
reg = EPPRegisterRead (0x0C);
if (reg != 0x04)
{
DBG (0,
"CmdGetBlockBuffer failed: unexpected value reg0C=0x%02X ...(%s:%d)\n",
reg, __FILE__, __LINE__);
return (0);
}
EPPREGISTERWRITE (0x0C, reg | 0x40);
/* there is always a full block ready when scanner is ready */
/* 32 bits I/O read , window must match the width of scan */
if (GetEPPMode () == 32)
EPPRead32Buffer (window, buffer + read);
else
EPPReadBuffer (window, buffer + read);
/* sum bytes read */
read += window;
DBG (16, "Read %d bytes out of %d (last block is %d bytes) (%s:%d)\n",
read, len, window, __FILE__, __LINE__);
/* test status after read */
reg = EPPRegisterRead (0x19) & 0xF8;
}
/* wait for the data to be ready */
gettimeofday (&td, NULL);
while ((reg & 0x08) == 0x08)
{
reg = EPPRegisterRead (0x19) & 0xF8;
gettimeofday (&tf, NULL);
elapsed =
((tf.tv_sec * 1000000 + tf.tv_usec) -
(td.tv_sec * 1000000 + td.tv_usec)) / 1000000;
if (elapsed > 3)
{
DBG
(0,
"Time-out (%.2f s) waiting for scanner ... giving up on status 0x%02X ! (%s:%d)\n",
elapsed, reg, __FILE__, __LINE__);
Epilogue ();
return (read);
}
}
if ((reg != 0xC0) && (reg != 0xD0) && (reg != 0x00))
{
DBG (0, "Unexpected status 0x%02X, expected 0xC0 or 0xD0 ! (%s:%d)\n",
reg, __FILE__, __LINE__);
DBG (0, "Going on...\n");
}
EPPREGISTERWRITE (0x0E, 0x0D);
EPPREGISTERWRITE (0x0F, 0x00);
/* OK ! */
Epilogue ();
return (read);
}
static void
Bloc2Decode (int *op)
{
int i;
int scanh;
int skiph;
int dpi = 0;
int dir = 0;
int color = 0;
char str[64];
for (i = 0; i < 16; i++)
sprintf (str + 3 * i, "%02X ", op[i]);
str[48] = 0x00;
DBG (0, "Command bloc 2: %s\n", str);
scanh = op[0] + (op[1] & 0x3F) * 256;
skiph = ((op[1] & 0xC0) >> 6) + (op[2] * 4) + ((op[3] & 0x0F) << 10);
if (op[3] & 0x10)
dir = 1;
else
dir = 0;
if (op[13] & 0x04)
color = 1;
else
color = 0;
if ((op[8] == 0x17) && (op[9] != 0x05))
dpi = 150;
if ((op[8] == 0x17) && (op[9] == 0x05))
dpi = 300;
if ((op[9] == 0x05) && (op[14] & 0x08))
dpi = 1200;
if ((dpi == 0) && ((op[14] & 0x08) == 0))
dpi = 600;
DBG (0, "\t->scan height =0x%04X (%d)\n", scanh, scanh);
DBG (0, "\t->skip height =0x%04X (%d)\n", skiph, skiph);
DBG (0, "\t->y dpi =0x%04X (%d)\n", dpi, dpi);
DBG (0, "\t->channel 1 gain=0x%02X (%d)\n", op[10] & 0x0F, op[10] & 0x0F);
DBG (0, "\t->channel 2 gain=0x%02X (%d)\n", (op[10] & 0xF0) / 16,
(op[10] & 0xF0) / 16);
DBG (0, "\t->channel 3 gain=0x%02X (%d)\n", op[11] & 0x0F, op[11] & 0x0F);
DBG (0, "\t->channel 1 high=0x%02X (%d)\n", (op[11] / 16) & 0x0F,
(op[11] / 16) & 0x0F);
DBG (0, "\t->channel 2 high=0x%02X (%d)\n", (op[12] & 0xF0) / 16,
(op[12] & 0xF0) / 16);
DBG (0, "\t->channel 3 high=0x%02X (%d)\n", op[12] & 0x0F, op[12] & 0x0F);
if (dir)
DBG (0, "\t->forward direction\n");
else
DBG (0, "\t->reverse direction\n");
if (color)
DBG (0, "\t->color scan \n");
else
DBG (0, "\t->no color scan \n");
DBG (0, "\n");
}
static void
Bloc8Decode (int *op)
{
int i, bpl;
int xskip;
int xend;
char str[128];
for (i = 0; i < 36; i++)
sprintf (str + 3 * i, "%02X ", op[i]);
str[3 * i] = 0x00;
DBG (0, "Command bloc 8: %s\n", str);
xskip = op[17] + 256 * (op[18] & 0x0F);
if (op[33] & 0x40)
xskip += 0x1000;
xend = (op[18] & 0xF0) / 16 + 16 * op[19];
if (op[33] & 0x80)
xend += 0x1000;
bpl = (op[24] - 0x41) * 256 + 8192 * (op[34] & 0x01) + op[23];
DBG (0, "\t->xskip =0x%X (%d)\n", xskip, xskip);
DBG (0, "\t->xend =0x%X (%d)\n", xend, xend);
DBG (0, "\t->scan width=0x%X (%d)\n", xend - xskip - 1, xend - xskip - 1);
DBG (0, "\t->bytes/line=0x%X (%d)\n", bpl, bpl);
DBG (0, "\n");
}
static int
CompletionWait (void)
{
CMDSYNC (0x40);
do
{
usleep (100000);
CMDSYNC (0xC2);
}
while ((sanei_umax_pp_ScannerStatus () & 0x90) != 0x90);
CMDSYNC (0xC2);
return (1);
}
int
sanei_umax_pp_SetLamp (int on)
{
int buffer[17];
int state;
/* reset? */
sanei_umax_pp_CmdSync (0x00);
sanei_umax_pp_CmdSync (0xC2);
sanei_umax_pp_CmdSync (0x00);
/* get status */
CmdGet (0x02, 16, buffer);
state = buffer[14] & LAMP_STATE;
buffer[16] = -1;
if ((state == 0) && (on == 0))
{
DBG (0, "Lamp already off ... (%s:%d)\n", __FILE__, __LINE__);
return (1);
}
if ((state) && (on))
{
DBG (2, "Lamp already on ... (%s:%d)\n", __FILE__, __LINE__);
return (1);
}
/* set lamp state */
if (on)
buffer[14] = buffer[14] | LAMP_STATE;
else
buffer[14] = buffer[14] & ~LAMP_STATE;
if (CmdSetGet (0x02, 16, buffer) != 1)
{
DBG (0, "CmdSetGet(0x02,16,buffer) failed (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
DBG (16, "CmdSetGet(0x02,16,buffer) passed ... (%s:%d)\n", __FILE__,
__LINE__);
return (1);
}
static int num = 0;
static void
Dump (int len, unsigned char *data, char *name)
{
FILE *fic;
char titre[80];
if (name == NULL)
{
sprintf (titre, "dump%04d.bin", num);
num++;
}
else
{
sprintf (titre, "%s", name);
}
fic = fopen (titre, "wb");
if (fic == NULL)
{
DBG (0, "could not open %s for writing\n", titre);
return;
}
fwrite (data, 1, len, fic);
fclose (fic);
}
static void
DumpNB (int width, int height, unsigned char *data, char *name)
{
FILE *fic;
char titre[80];
if (name == NULL)
{
sprintf (titre, "dump%04d.pnm", num);
num++;
}
else
{
sprintf (titre, "%s", name);
}
fic = fopen (titre, "wb");
if (fic == NULL)
{
DBG (0, "could not open %s for writing\n", titre);
return;
}
fprintf (fic, "P5\n%d %d\n255\n", width, height);
fwrite (data, width, height, fic);
fclose (fic);
}
static void
DumpRVB (int width, int height, unsigned char *data, char *name)
{
FILE *fic;
char titre[80];
int y, x;
if (name == NULL)
{
sprintf (titre, "dump%04d.pnm", num);
num++;
}
else
{
sprintf (titre, "%s", name);
}
fic = fopen (titre, "wb");
fprintf (fic, "P6\n%d %d\n255\n", width, height);
if (fic == NULL)
{
DBG (0, "could not open %s for writing\n", titre);
return;
}
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
fputc (data[3 * y * width + 2 * width + x], fic);
fputc (data[3 * y * width + width + x], fic);
fputc (data[3 * y * width + x], fic);
}
}
fclose (fic);
}
static void
ComputeCalibrationData (int color, int dpi, int width, unsigned char *source,
int *data)
{
int p, i, l;
int sum, gn;
memset (data, 0, (3 * 5100 + 768 + 3) * sizeof (int));
/* 0 -> 5099 */
for (i = 0; i < width; i++)
{ /* red calibration data */
if (color >= RGB_MODE)
{
/* compute average */
sum = 0;
for (l = 0; l < 66; l++)
sum += source[i + l * 5100 * 3];
gn = (int) (((double) (250 * l) / sum - 0.984) * 102.547 + 0.5);
if (gn < 0)
gn = 0;
else if (gn > 255)
gn = 255;
data[i] = gn;
}
else
data[i] = 0x00;
}
/* 5100 -> 10199: green data */
p = 5100;
for (i = 0; i < width; i++)
{
/* compute average */
sum = 0;
for (l = 0; l < 66; l++)
sum += source[i + l * 5100 * 3 + 5100];
gn = (int) (((double) (250 * l) / sum - 0.984) * 102.547 + 0.5);
if (gn < 0)
gn = 0;
else if (gn > 255)
gn = 255;
data[p + i] = gn;
}
/* 10200 -> 15299: blue */
p = 10200;
for (i = 0; i < width; i++)
{
if (color >= RGB_MODE)
{
/* compute average */
sum = 0;
for (l = 0; l < 66; l++)
sum += source[i + l * 5100 * 3 + 5100 * 2];
gn = (int) (((double) (250 * l) / sum - 0.984) * 102.547 + 0.5);
if (gn < 0)
gn = 0;
else if (gn > 255)
gn = 255;
data[p + i] = gn;
}
else
data[p + i] = 0x00;
}
/* gamma tables */
for (i = 0; i < 256; i++)
data[15300 + i] = ggRed[i];
for (i = 0; i < 256; i++)
data[15300 + 256 + i] = ggGreen[i];
for (i = 0; i < 256; i++)
data[15300 + 512 + i] = ggBlue[i];
if (color >= RGB_MODE)
{
switch (dpi)
{
case 1200:
case 600:
data[16068] = 0xFF;
data[16069] = 0xFF;
break;
case 300:
data[16068] = 0xAA;
data[16069] = 0xFF;
break;
case 150:
data[16068] = 0x88;
data[16069] = 0xFF;
break;
case 75:
data[16068] = 0x80;
data[16069] = 0xAA;
break;
}
}
else
{
switch (dpi)
{
case 1200:
case 600:
data[16068] = 0xFF;
data[16069] = 0xFF;
break;
case 300:
data[16068] = 0xAA;
data[16069] = 0xFF;
break;
case 150:
data[16068] = 0x88;
data[16069] = 0xAA;
break;
case 75:
data[16068] = 0x80;
data[16069] = 0x88;
break;
}
}
data[16070] = -1;
}
/* move head by the distance given using precision or not */
/* 0: failed
1: success */
static int
Move (int distance, int precision, unsigned char *buffer)
{
int header[17] = { 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x60, 0x2F,
0x2F, 0x01, 0x00, 0x00, 0x00, 0x80, 0xA4, 0x00, -1
};
int body[37] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
0x6E, 0xF6, 0x79, 0xBF, 0x01, 0x00, 0x00, 0x00,
0x46, 0xA0, 0x00, 0x8B, 0x49, 0x2A, 0xE9, 0x68,
0xDF, 0x13, 0x1A, 0x00, -1
};
int end[9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, -1 };
int steps, len;
unsigned char tmp[0x200];
unsigned char *ptr;
if (distance == 0)
return (0);
if (buffer == NULL)
ptr = tmp;
else
ptr = buffer;
/* build commands */
if (distance < 0)
{
/* header */
steps = -distance - 1;
header[3] = 0x20;
header[9] = 0x01;
/* reverse direction body by default */
/* end */
end[1] = 0xFF;
end[2] = 0xFF;
end[3] = -1;
len = 3;
}
else
{
/* header */
steps = distance - 1;
header[3] = 0x70;
header[9] = 0x05;
/* body */
body[2] = 0x04;
body[4] = 0x02;
body[7] = 0x0C;
body[9] = 0x04;
body[10] = 0x40;
body[11] = 0x01;
/* end */
len = 8;
}
if (steps > 0)
{
header[1] = (steps << 6) & 0xFF;
header[2] = (steps >> 2) & 0xFF;
header[3] = header[3] | ((steps >> 10) & 0x0F);
}
/* precision: default header set to precision on */
if (precision == PRECISION_OFF)
{
if (sanei_umax_pp_getastra () == 1600)
header[8] = 0x15;
else
header[8] = 0x17;
header[14] = 0xAC;
body[20] = 0x06;
}
if (DBG_LEVEL >= 128)
{
Bloc2Decode (header);
Bloc8Decode (body);
}
CMDSETGET (0x02, 16, header);
CMDSETGET (0x08, 36, body);
if (DBG_LEVEL >= 128)
{
Bloc2Decode (header);
Bloc8Decode (body);
}
CMDSYNC (0xC2);
if (sanei_umax_pp_ScannerStatus () & 0x80)
{
CMDSYNC (0x00);
}
CMDSETGET (4, len, end);
COMPLETIONWAIT;
if (DBG_LEVEL >= 128)
{
Dump (0x200, ptr, NULL);
}
CMDGETBUF (4, 0x200, ptr);
DBG (16, "MOVE STATUS IS 0x%02X (%s:%d)\n", sanei_umax_pp_ScannerStatus (),
__FILE__, __LINE__);
CMDSYNC (0x00);
return (1);
}
/* for each column, finds the row where white/black transition occurs
then returns the average */
static float
EdgePosition (int width, int height, unsigned char *data)
{
int ecnt, x, y;
float epos;
int d, dmax, dpos;
epos = 0;
ecnt = 0;
for (x = 0; x < width; x++)
{
/* first edge: white->black */
dmax = 0;
dpos = 0;
for (y = 1; y < height; y++)
{
d = data[x + (y - 1) * width] - data[x + y * width];
if (d > dmax)
{
dmax = d;
dpos = y;
}
}
if (dmax > 0)
{
epos += dpos;
ecnt++;
}
}
if (ecnt == 0)
epos = 70;
else
epos = epos / ecnt;
return (epos);
}
static int
MoveToOrigin (void)
{
unsigned char buffer[54000];
float edge;
int val, delta;
int header[17] = { 0xB4, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x2F,
0x2F, 0x05, 0x00, 0x00, 0x00, 0x80, 0xA4, 0x00, -1
};
int body[37] = { 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C,
0x00, 0x04, 0x40, 0x01, 0x00, 0x00, 0x04, 0x00,
0x6E, 0xFB, 0xC4, 0xE5, 0x06, 0x00, 0x00, 0x60,
0x4D, 0xA0, 0x00, 0x8B, 0x49, 0x2A, 0xE9, 0x68,
0xDF, 0x13, 0x1A, 0x00, -1
};
int end[9] = { 0x06, 0xF4, 0xFF, 0x81, 0x1B, 0x00, 0x08, 0x00, -1 };
int opsc03[9] = { 0x00, 0x00, 0x00, 0xAA, 0xCC, 0xEE, 0x80, 0xFF, -1 };
/* 1600P command set */
if (sanei_umax_pp_getastra () == 1600)
{
header[8] = 0x2B;
body[29] = 0x1A;
body[30] = 0xEE;
end[0] = 0x19;
end[1] = 0xD5;
end[4] = 0x1B;
}
/* sync scanner then move head by the estimated origin */
CMDSYNC (0x00);
CMDSYNC (0xC2);
CMDSYNC (0x00);
MOVE (196, PRECISION_OFF, NULL);
/* scan 2400 'x' by 180 y, B&W at 600 dpi, starting at the */
/* first quarter of the x area. This should cover a black */
/* line drawn in the middle of a white area, under the piece */
/* that separates the 'little' window and the scan window */
CMDSETGET (0x02, 16, header);
CMDSETGET (0x08, 36, body);
if (DBG_LEVEL > 128)
{
Bloc2Decode (header);
Bloc8Decode (body);
}
CMDSETGET (0x01, 8, end);
CMDSYNC (0xC2);
CMDSYNC (0x00);
/* signals black & white ? */
CMDSETGET (0x04, 8, opsc03);
COMPLETIONWAIT;
CMDGETBUF (0x04, 54000, buffer); /* get find position data */
if (DBG_LEVEL > 128)
{
DumpNB (300, 180, buffer, NULL);
}
/* detection of 1600P is a by product of origin finding */
edge = 0.0;
for (val = 0; val < 54000; val++)
if (buffer[val] > edge)
edge = buffer[val];
DBG (32, "MAX VALUE=%f (%s:%d)\n", edge, __FILE__, __LINE__);
if ((edge <= 30) && (sanei_umax_pp_getastra () != 1600))
{
DBG (2, "MoveToOrigin() detected a 1600P");
sanei_umax_pp_setastra (1600);
}
edge = EdgePosition (300, 180, buffer);
/* rounded to lowest integer, since upping origin might lead */
/* to bump in the other side if doing a preview */
val = (int) (edge);
/* edge is 60 dots (at 600 dpi) from origin */
/* origin=current pos - 180 + edge + 60 */
/* grumpf, there is an offset somewhere ... */
delta = -180 + edge - 8;
DBG (64, "Edge=%f, val=%d, delta=%d\n", edge, val, delta);
/* move back to y-coordinate origin */
MOVE (delta, PRECISION_ON, NULL);
/* head successfully set to the origin */
return (1);
}
/* computes color offset and gain */
/* X is red
Y is blue
Z is green
returns if OK, else 0
*/
static int
WarmUp (int color, int *gain)
{
unsigned char buffer[5300];
int i, val;
int opsc02[9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, -1 };
int opsc04[9] = { 0x06, 0xF4, 0xFF, 0x81, 0x1B, 0x00, 0x00, 0x00, -1 };
int opsc10[9] = { 0x06, 0xF4, 0xFF, 0x81, 0x1B, 0x00, 0x08, 0x00, -1 };
int opsc18[17] =
{ 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x2F, 0x2F, 0x00, 0x88, 0x08,
0x00, 0x80, 0xA4, 0x00, -1
};
int opsc38[37] =
{ 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x00, 0x04, 0x40, 0x01,
0x00, 0x00, 0x04, 0x00, 0x6E, 0x18, 0x10, 0x03, 0x06, 0x00, 0x00, 0x00,
0x46, 0xA0, 0x00, 0x8B, 0x49, 0x2A, 0xE9, 0x68, 0xDF, 0x13, 0x1A, 0x00,
-1
};
int opsc39[37] =
{ 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x00, 0x04, 0x40, 0x01,
0x00, 0x00, 0x04, 0x00,
0x6E, 0x41, 0x20, 0x24, 0x06, 0x00, 0x00, 0x00, 0x46, 0xA0, 0x00, 0x8B,
0x49, 0x2A, 0xE9, 0x68,
0xDF, 0x13, 0x1A, 0x00, -1
};
int opsc40[37] =
{ 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x00, 0x04, 0x40, 0x01,
0x00, 0x00, 0x04, 0x00, 0x6E, 0x41, 0x60, 0x4F, 0x06, 0x00, 0x00, 0x00,
0x46, 0xA0, 0x00, 0x8B, 0x49, 0x2A, 0xE9, 0x68, 0xDF, 0x93, 0x1A, 0x00,
-1
};
int opsc51[17] =
{ 0x09, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x2F, 0x2F, 0x00, 0xA5, 0x09,
0x00, 0x40, 0xA4, 0x00, -1
};
int opsc48[17] =
{ 0x09, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x2F, 0x2F, 0x00, 0x00, 0x00,
0x00, 0x40, 0xA4, 0x00, -1
};
float offsetX, offsetY, offsetZ;
float avgX, avgY, avgZ;
/* really dirty hack: somethig is buggy in BW mode */
/* we override mode with color until the bug is found */
color = RGB_MODE;
/* 1600P have a different CCD command block */
if (sanei_umax_pp_getastra () == 1600)
{
opsc04[0] = 0x19;
opsc04[1] = 0xD5;
opsc04[4] = 0x1B;
opsc04[7] = 0x20;
opsc10[0] = 0x19;
opsc10[1] = 0xD5;
opsc10[4] = 0x1B;
opsc10[7] = 0x20;
opsc48[8] = 0x2B;
opsc48[11] = 0x20;
opsc48[12] = 0x08;
opsc48[13] = 0x42;
}
/* block that repeats : another kind of move .... */
/* scan one line of 24 bytes at the right/left */
/* maybe black calibration since it is out of the */
/* scanning area */
/* color calibration: offset detection */
/* scan 24 pixels wide, 1 pixel height at 600 dpi */
/* without moving the head. Pixels are 'under the */
/* roof', so should be black */
if (color >= RGB_MODE)
{
CMDSETGET (2, 0x10, opsc48);
CMDSETGET (8, 0x24, opsc38);
CMDSETGET (1, 0x08, opsc04); /* scan std, no 'enhancing' */
CMDSYNC (0xC2);
if (sanei_umax_pp_ScannerStatus () & 0x80)
{
CMDSYNC (0x00);
}
CMDSETGET (4, 0x08, opsc02); /* commit ? */
COMPLETIONWAIT;
CMDGETBUF (4, 0x18, buffer);
if (DBG_LEVEL >= 128)
Dump (0x18, buffer, NULL);
val = 0;
for (i = 0; i < 24; i++)
val += buffer[i];
offsetX = (float) val / i;
CMDSYNC (0x00);
opsc04[7] = opsc04[7] | 0x10; /* enhanced ? */
CMDSETGET (1, 0x08, opsc04);
COMPLETIONWAIT;
CMDGETBUF (4, 0x18, buffer);
val = 0;
for (i = 0; i < 24; i++)
val += buffer[i];
offsetX += (float) val / i;
if (DBG_LEVEL >= 128)
Dump (0x18, buffer, NULL);
/* block that repeats */
/* must be monochrome since hscan=1 */
opsc48[0] = 0x01;
if (sanei_umax_pp_getastra () == 1600)
{
opsc48[12] = 0x0C;
opsc48[13] = 0x82;
}
else
{
opsc48[12] = 0x04;
opsc48[13] = 0x80;
}
CMDSETGET (2, 0x10, opsc48);
CMDSETGET (8, 0x24, opsc38);
opsc04[7] = opsc04[7] & 0x20;
CMDSETGET (1, 0x08, opsc04);
CMDSYNC (0xC2);
if (sanei_umax_pp_ScannerStatus () & 0x80)
{
CMDSYNC (0x00);
}
CMDSETGET (4, 0x08, opsc02);
COMPLETIONWAIT;
CMDGETBUF (4, 0x18, buffer);
if (DBG_LEVEL >= 128)
Dump (0x18, buffer, NULL);
val = 0;
for (i = 0; i < 24; i++)
val += buffer[i];
offsetY = (float) val / i;
CMDSYNC (0x00);
opsc04[7] = opsc04[7] | 0x10; /* brightness ? */
CMDSETGET (1, 0x08, opsc04);
COMPLETIONWAIT;
CMDGETBUF (4, 0x18, buffer);
if (DBG_LEVEL >= 128)
Dump (0x18, buffer, NULL);
val = 0;
for (i = 0; i < 24; i++)
val += buffer[i];
offsetY += (float) val / i;
}
/* block that repeats */
if (color < RGB_MODE)
{
opsc48[0] = 0x05; /* B&H height is 5 */
opsc48[13] = 0xC0; /* B&W mode */
}
else
{
opsc48[0] = 0x05; /* color height is 5 (+4 ?) */
opsc48[13] = 0xC1; /* some strange mode ? */
}
if (sanei_umax_pp_getastra () == 1600)
opsc48[13] = opsc48[13] | 0x02;
CMDSETGET (2, 0x10, opsc48);
CMDSETGET (8, 0x24, opsc38);
opsc04[7] = opsc04[7] & 0x20;
CMDSETGET (1, 0x08, opsc04);
CMDSYNC (0xC2);
if (sanei_umax_pp_ScannerStatus () & 0x80)
{
CMDSYNC (0x00);
}
CMDSETGET (4, 0x08, opsc02);
COMPLETIONWAIT;
CMDGETBUF (4, 0x18, buffer);
if (DBG_LEVEL >= 128)
Dump (0x18, buffer, NULL);
val = 0;
for (i = 0; i < 24; i++)
val += buffer[i];
offsetZ = (float) val / i;
CMDSYNC (0x00);
opsc04[7] = opsc04[7] | 0x10;
CMDSETGET (1, 0x08, opsc04);
COMPLETIONWAIT;
CMDGETBUF (4, 0x18, buffer);
if (DBG_LEVEL >= 128)
Dump (0x18, buffer, NULL);
val = 0;
for (i = 0; i < 24; i++)
val += buffer[i];
offsetZ += (float) val / i;
/***********************/
/* auto gain computing */
/***********************/
/* color correction set to 63 06 */
/* for a start */
*gain = 0x636;
CMDSETGET (2, 0x10, opsc18);
CMDSETGET (8, 0x24, opsc39);
opsc04[7] = opsc04[7] & 0x20;
opsc04[6] = 0x06; /* one channel gain value */
CMDSETGET (1, 0x08, opsc10); /* was opsc04, extraneaous string */
/* that prevents using Move .... */
CMDSYNC (0xC2);
CMDSYNC (0x00);
CMDSETGET (4, 0x08, opsc02);
COMPLETIONWAIT;
CMDGETBUF (4, 0x200, buffer);
if (DBG_LEVEL >= 128)
Dump (0x200, buffer, NULL);
/* auto correction of gain levels */
/* first color component X */
opsc51[10] = (*gain) / 16; /* channel 1 & 2 gain */
opsc51[11] = (*gain) % 16; /* channel 3 gain */
if (color >= RGB_MODE)
{
if (sanei_umax_pp_getastra () == 1600)
{
opsc51[11] |= 0x20;
opsc51[12] = 0x08;
opsc51[13] |= 0x02;
opsc04[7] |= 0x20;
}
CMDSETGET (2, 0x10, opsc51);
CMDSETGET (8, 0x24, opsc40);
if (DBG_LEVEL >= 128)
{
Bloc2Decode (opsc51);
Bloc8Decode (opsc40);
}
opsc04[6] = (*gain) / 256;
CMDSETGET (1, 0x08, opsc04);
CMDSYNC (0xC2);
CMDSYNC (0x00);
CMDSETGET (4, 0x08, opsc02);
COMPLETIONWAIT;
CMDGETBUF (4, 0x14B4, buffer);
if (DBG_LEVEL >= 128)
Dump (0x14B4, buffer, NULL);
avgX = 0;
for (i = 0; i < 0x14B4; i++)
avgX += buffer[i];
avgX = avgX / i;
DBG (64, "Somme(X:%02X)=%d, moyenne=%8.4f(%f)\n", opsc04[6],
(int) (avgX * i), avgX, avgX - offsetX);
while ((opsc04[6] < 0x0F) && (avgX - offsetX < 180.0))
{
CMDSYNC (0x00);
opsc04[6]++;
CMDSETGET (1, 0x000008, opsc04);
COMPLETIONWAIT;
CMDGETBUF (4, 0x0014B4, buffer);
if (DBG_LEVEL >= 128)
Dump (0x14B4, buffer, NULL);
avgX = 0;
for (i = 0; i < 0x14B4; i++)
avgX += buffer[i];
avgX = avgX / i;
DBG (16, "Somme(X:%02X)=%d, moyenne=%8.4f(%f)\n", opsc04[6],
(int) (avgX * i), avgX, avgX - offsetX);
}
*gain = (*gain & 0xFF) + 256 * (opsc04[6] - 1);
opsc51[10] = *gain / 16; /* channel 1 & 2 gain */
opsc51[11] = *gain % 16; /* channel 3 gain */
opsc51[0] = 0x01;
opsc51[13] = 0x80;
if (sanei_umax_pp_getastra () == 1600)
{
opsc51[11] |= 0x20;
opsc51[12] = 0x08;
opsc51[13] |= 0x02;
opsc04[7] |= 0x20;
}
CMDSETGET (2, 0x10, opsc51);
CMDSETGET (8, 0x24, opsc40);
opsc04[6] = (*gain & 0x00F);
CMDSETGET (1, 0x08, opsc04);
CMDSYNC (0xC2);
CMDSYNC (0x00);
CMDSETGET (4, 0x08, opsc02);
COMPLETIONWAIT;
CMDGETBUF (4, 0x14B4, buffer);
if (DBG_LEVEL >= 128)
Dump (0x14B4, buffer, NULL);
avgY = 0;
for (i = 0; i < 0x14B4; i++)
avgY += buffer[i];
avgY = avgY / i;
DBG (64, "Somme(Y:%02X)=%d, moyenne=%8.4f(%f)\n", opsc04[6],
(int) (avgY * i), avgY, avgY - offsetY);
while ((opsc04[6] < 0x0F) && (avgY - offsetY < 180.0))
{
CMDSYNC (0x00);
opsc04[6]++;
CMDSETGET (1, 0x000008, opsc04);
COMPLETIONWAIT;
CMDGETBUF (4, 0x0014B4, buffer);
if (DBG_LEVEL >= 128)
Dump (0x14B4, buffer, NULL);
avgY = 0;
for (i = 0; i < 0x14B4; i++)
avgY += buffer[i];
avgY = avgY / i;
DBG (64, "Somme(Y:%02X)=%d, moyenne=%8.4f(%f)\n", opsc04[6],
(int) (avgY * i), avgY, avgY - offsetY);
}
*gain = (*gain & 0xFF0) + (opsc04[6] - 1);
}
/* component Z: B&W component */
opsc51[10] = *gain / 16; /* channel 1 & 2 gain */
opsc51[11] = *gain % 16; /* channel 3 gain */
if (color < RGB_MODE)
opsc51[0] = 0x01; /* in BW, scan zone doesn't have an extra 4 points */
else
opsc51[0] = 0x05; /* extra 4 points */
opsc51[13] = 0xC0; /* B&W */
if (sanei_umax_pp_getastra () == 1600)
{
opsc51[11] |= 0x20;
opsc51[12] = 0x08;
opsc51[13] |= 0x02;
opsc04[7] |= 0x20;
}
CMDSETGET (2, 0x10, opsc51);
if (DBG_LEVEL >= 128)
{
Bloc2Decode (opsc51);
}
CMDSETGET (8, 0x24, opsc40);
opsc04[6] = (*gain & 0x0F0) / 16;
CMDSETGET (1, 0x08, opsc04);
CMDSYNC (0xC2);
CMDSYNC (0x00);
CMDSETGET (4, 0x08, opsc02);
COMPLETIONWAIT;
CMDGETBUF (4, 0x14B4, buffer);
if (DBG_LEVEL >= 128)
Dump (0x14B4, buffer, NULL);
avgZ = 0;
for (i = 0; i < 0x14B4; i++)
avgZ += buffer[i];
avgZ = avgZ / i;
DBG (64, "Somme(Z:%02X)=%d, moyenne=%8.4f(%f)\n", opsc04[6],
(int) (avgZ * i), avgZ, avgZ - offsetZ);
while ((opsc04[6] < 0x07) && (avgZ - offsetZ < 180.0))
{
CMDSYNC (0x00);
opsc04[6]++;
CMDSETGET (1, 0x08, opsc04);
COMPLETIONWAIT;
CMDGETBUF (4, 0x0014B4, buffer);
if (DBG_LEVEL >= 128)
Dump (0x14B4, buffer, NULL);
avgZ = 0;
for (i = 0; i < 0x14B4; i++)
avgZ += buffer[i];
avgZ = avgZ / i;
DBG (64, "Somme(Z:%02X)=%d, moyenne=%8.4f(%f)\n", opsc04[6],
(int) (avgZ * i), avgZ, avgZ - offsetZ);
}
*gain = (*gain & 0xF0F) + opsc04[6] * 16;
DBG (1, "Warm-up done ...\n");
return (1);
}
/* park head: returns 1 on success, 0 otherwise */
/* distance is in 75 dpi unit */
int
sanei_umax_pp_Park (void)
{
int header[17] =
{ 0x01, 0x00, 0x01, 0x70, 0x00, 0x00, 0x60, 0x2F, 0x13, 0x05, 0x00, 0x00,
0x00, 0x80, 0xF0, 0x00, -1
};
int body[37] =
{ 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x00, 0x03, 0xC1, 0x80,
0x00, 0x00, 0x04, 0x00, 0x16, 0x80, 0x15, 0x78, 0x03, 0x03, 0x00, 0x00,
0x46, 0xA0, 0x00, 0x8B, 0x49, 0x2A, 0xE9, 0x68, 0xDF, 0x1B, 0x1A, 0x00,
-1
};
int status = 0x90;
CMDSYNC (0x00);
CMDSETGET (0x02, 16, header);
if (DBG_LEVEL >= 32)
Bloc8Decode (body);
CMDSETGET (0x08, 36, body);
CMDSYNC (0x40);
status = sanei_umax_pp_ScannerStatus ();
DBG (16, "PARKING STATUS is 0x%02X (%s:%d)\n", status, __FILE__, __LINE__);
DBG (1, "Park command issued ...\n");
return (1);
}
/* calibrates CCD: returns 1 on success, 0 on failure */
static int
GammaCalibration (int color, int dpi, int gain, int highlight, int width,
int *calibration)
{
int opsc32[17] =
{ 0x4A, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x00, 0x17, 0x05, 0xA5, 0x08,
0x00, 0x00, 0xAC, 0x00, -1
};
int opsc41[37] =
{ 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x00, 0x04, 0x40, 0x01,
0x00, 0x00, 0x04, 0x00, 0x6E, 0x90, 0xD0, 0x47, 0x06, 0x00, 0x00, 0xC4,
0x5C, 0xA0, 0x00, 0x8B, 0x49, 0x2A, 0xE9, 0x68, 0xDF, 0x93, 0x1B, 0x00,
-1
};
int opscnb[37] =
{ 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x00, 0x04, 0x40, 0x01,
0x00, 0x00, 0x04, 0x00, 0x6E, 0x90, 0xD0, 0x47, 0x06, 0x00, 0x00, 0xEC,
0x54, 0xA0, 0x00, 0x8B, 0x49, 0x2A, 0xE9, 0x68, 0xDF, 0x93, 0x1A, 0x00,
-1
};
int opsc04[9] = { 0x06, 0xF4, 0xFF, 0x81, 0x1B, 0x00, 0x00, 0x00, -1 };
int opsc02[9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, -1 };
int size;
unsigned char buffer[0x105798];
/* 1600P have a different CCD command block */
if (sanei_umax_pp_getastra () == 1600)
{
opsc04[0] = 0x19;
opsc04[1] = 0xD5;
opsc04[4] = 0x1B;
opsc41[29] = 0x1A;
opsc41[30] = 0xEE;
}
/* step back by 66 ticks: */
/* since we're going to scan 66 lines of data */
/* which are going to be used as calibration */
/* data */
/* we are on the white area just before */
/* the user scan area */
MOVE (-67, PRECISION_ON, NULL);
CMDSYNC (0x00);
/* get calibration data */
opsc32[10] = gain / 16;
opsc32[11] = ((highlight / 16) & 0xF0) | (gain % 16);
opsc32[12] = highlight % 256;
if (sanei_umax_pp_getastra () == 1600)
{
opsc32[13] = 0x03;
}
if (color < RGB_MODE)
{
opsc32[0] -= 4;
opsc32[13] = 0xC0;
}
CMDSETGET (2, 0x10, opsc32);
if (DBG_LEVEL >= 64)
{
Bloc2Decode (opsc32);
}
if (color < RGB_MODE)
{
CMDSETGET (8, 0x24, opscnb);
if (DBG_LEVEL >= 64)
{
Bloc8Decode (opscnb);
}
opsc04[6] = 0x85;
}
else
{
CMDSETGET (8, 0x24, opsc41);
if (DBG_LEVEL >= 64)
{
Bloc8Decode (opsc41);
}
opsc04[6] = 0x0F;
if (sanei_umax_pp_getastra () == 1600)
opsc04[7] = 0xC0;
else
opsc04[7] = 0x70;
}
/* BUG BW noisy here */
CMDSETGET (1, 0x08, opsc04);
CMDSYNC (0xC2);
CMDSYNC (0x00);
CMDSETGET (4, 0x08, opsc02); /* opsc03 hangs it */
COMPLETIONWAIT;
opsc04[0] = 0x06;
if (color >= RGB_MODE)
size = 3 * 5100 * 70;
else
size = 5100 * 66;
if (GetEPPMode () == 32)
{
CmdGetBuffer32 (4, size, buffer);
}
else
{
CMDGETBUF (4, size, buffer);
}
if (DBG_LEVEL >= 128)
{
Dump (size, buffer, NULL);
if (color >= RGB_MODE)
{
DumpRVB (5100, 70, buffer, NULL);
}
else
{
DumpNB (5100, 66, buffer, NULL);
}
}
ComputeCalibrationData (color, dpi, width, buffer, calibration);
DBG (1, "Gamma calibration done ...\n");
return (1);
}
/* returns number of bytes read or 0 on failure */
int
sanei_umax_pp_ReadBlock (long len, int window, int dpi, int last,
unsigned char *buffer)
{
DBG (8, "ReadBlock(%ld,%d,%d,%d)\n", len, window, dpi, last);
/* EPP block reading is available only when dpi >=600 */
if (dpi >= 600)
{
DBG (8, "CmdGetBlockBuffer(4,%ld,%d);\n", len, window);
len = CmdGetBlockBuffer (4, len, window, buffer);
if (len == 0)
{
DBG (0, "CmdGetBlockBuffer(4,%ld,%d) failed (%s:%d)\n", len, window,
__FILE__, __LINE__);
gCancel = 1;
}
}
else
{
DBG (8, "CmdGetBuffer(4,%ld);\n", len);
if (CmdGetBuffer (4, len, buffer) != 1)
{
DBG (0, "CmdGetBuffer(4,%ld) failed (%s:%d)\n", len, __FILE__,
__LINE__);
gCancel = 1;
}
}
if (!last)
{
/* sync with scanner */
if (sanei_umax_pp_CmdSync (0xC2) == 0)
{
DBG (0, "Warning CmdSync(0xC2) failed! (%s:%d)\n", __FILE__,
__LINE__);
DBG (0, "Trying again ... ");
if (sanei_umax_pp_CmdSync (0xC2) == 0)
{
DBG (0, " failed again! (%s:%d)\n", __FILE__, __LINE__);
DBG (0, "Aborting ...\n");
gCancel = 1;
}
else
DBG (0, " success ...\n");
}
}
return (len);
}
int
sanei_umax_pp_Scan (int x, int y, int width, int height, int dpi, int color,
int gain, int highlight)
{
struct timeval td, tf;
unsigned char *buffer;
long int somme, len, read, blocksize;
float elapsed;
FILE *fout = NULL;
int *dest = NULL;
int bpl, hp;
int th, tw, bpp;
int distance = 0, nb;
int bx, by;
if (sanei_umax_pp_StartScan
(x, y, width, height, dpi, color, gain, highlight, &bpp, &tw, &th) == 1)
{
COMPLETIONWAIT;
/* blocksize must be multiple of the number of bytes per line */
/* max is 2096100 */
/* so blocksize will hold a round number of lines, easing the */
/* write data to file operation */
/*blocksize=(2096100/bpl)*bpl; */
bpl = bpp * tw;
hp = 2096100 / bpl;
hp = 16776960 / bpl;
blocksize = hp * bpl;
nb = 0;
read = 0;
/* get scanned data */
somme = bpp * tw * th;
DBG (8, "Getting buffer %d*%d*%d=%ld=0x%lX (%s:%d) \n", bpp, tw, th,
somme, somme, __FILE__, __LINE__);
/* allocate memory */
buffer = (unsigned char *) malloc (blocksize);
if (buffer == NULL)
{
DBG (0, "Failed to allocate %ld bytes, giving up....\n", blocksize);
DBG (0, "Try to scan at lower resolution, or a smaller area.\n");
gCancel = 1;
}
/* open output file */
fout = fopen ("out.pnm", "wb");
if (fout == NULL)
{
DBG (0, "Failed to open 'out.pnm', giving up....\n");
gCancel = 1;
}
else
{
/* write pnm header */
if (color >= RGB_MODE)
fprintf (fout, "P6\n%d %d\n255\n", bpl / bpp, th);
else
fprintf (fout, "P5\n%d %d\n255\n", bpl / bpp, th);
}
/* data reading loop */
gettimeofday (&td, NULL);
while ((read < somme) && (!gCancel))
{
/* 2096100 max */
if (somme - read > blocksize)
len = blocksize;
else
len = somme - read;
len =
sanei_umax_pp_ReadBlock (len, bpl / bpp, dpi, (len < blocksize),
buffer);
if (len == 0)
{
DBG (0, "ReadBlock failed, cancelling scan ...\n");
gCancel = 1;
}
read += len;
nb++;
DBG (8, "Read %ld bytes out of %ld ...\n", read, somme);
DBG (8, "Read %d blocks ... \n", nb);
/* write partial buffer to file */
if (len)
{
if (color >= RGB_MODE)
{
/* using an image format that doesn't need */
/* reordering would speed up write operation */
hp = len / bpl;
if (sanei_umax_pp_getastra () != 1600)
{
for (by = 0; by < hp; by++)
{
for (bx = 0; bx < tw; bx++)
{
fputc (buffer[3 * by * tw + 2 * tw + bx], fout);
fputc (buffer[3 * by * tw + tw + bx], fout);
fputc (buffer[3 * by * tw + bx], fout);
}
}
}
else
{
for (by = 0; by < hp; by++)
{
for (bx = 0; bx < tw; bx++)
{
fputc (buffer[3 * by * tw + 2 * tw + bx], fout);
fputc (buffer[3 * by * tw + bx], fout);
fputc (buffer[3 * by * tw + tw + bx], fout);
}
}
}
}
else
fwrite (buffer, len, 1, fout);
}
}
gettimeofday (&tf, NULL);
/* release ressources */
if (fout != NULL)
fclose (fout);
free (dest);
free (buffer);
/* scan time are high enough to forget about usec */
elapsed = tf.tv_sec - td.tv_sec;
DBG (8, "%ld bytes transfered in %f seconds ( %.2f Kb/s)\n", somme,
elapsed, (somme / elapsed) / 1024.0);
/* park head */
distance = distance + y + height;
} /* if start scan OK */
else
{
DBG (0, "StartScan failed..... \n");
}
/* terminate any pending command */
if (sanei_umax_pp_CmdSync (0x00) == 0)
{
DBG (0, "Warning CmdSync(0x00) failed! (%s:%d)\n", __FILE__, __LINE__);
DBG (0, "Trying again ... ");
if (sanei_umax_pp_CmdSync (0x00) == 0)
{
DBG (0, " failed again! (%s:%d)\n", __FILE__, __LINE__);
DBG (0, "Blindly going on ...\n");
}
else
DBG (0, " success ...\n");
}
/* parking */
if (sanei_umax_pp_Park () == 0)
DBG (0, "Park failed !!! (%s:%d)\n", __FILE__, __LINE__);
/* end ... */
DBG (1, "Scan done ...\n");
return (1);
}
int
sanei_umax_pp_ParkWait (void)
{
int status;
/* check if head is at home */
do
{
sleep (2);
sanei_umax_pp_CmdSync (0x40);
status = sanei_umax_pp_ScannerStatus ();
}
while ((status & MOTOR_BIT) == 0x00);
DBG (1, "ParkWait done ...\n");
return (1);
}
/* starts scan: return 1 on success */
int
sanei_umax_pp_StartScan (int x, int y, int width, int height, int dpi,
int color, int gain, int highlight, int *rbpp,
int *rtw, int *rth)
{
unsigned char *buffer;
int *dest = NULL;
int state[16];
int err = 0;
int calibration[3 * 5100 + 768 + 2 + 1];
int xdpi, ydpi, bpl, h;
int th, tw, bpp;
int distance, i;
int opsc04[9] = { 0x06, 0xF4, 0xFF, 0x81, 0x1B, 0x00, 0x00, 0x00, -1 };
int opsc53[17] =
{ 0xA4, 0x80, 0x07, 0x50, 0xEC, 0x03, 0x00, 0x2F, 0x17, 0x07, 0x84, 0x08,
0x00, 0x00, 0xAC, 0x00, -1
};
int opsc35[37] =
{ 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x00, 0x03, 0xC1, 0x80,
0x00, 0x00, 0x04, 0x00, 0x16, 0x41, 0xE0, 0xAC, 0x03, 0x03, 0x00, 0x00,
0x46, 0xA0, 0x00, 0x8B, 0x49, 0x2A, 0xE9, 0x68, 0xDF, 0x13, 0x1A, 0x00,
-1
};
int opscan[37] =
{ 0x00, 0x00, 0xB0, 0x4F, 0xD8, 0xE7, 0xFA, 0x10, 0xEF, 0xC4, 0x3C, 0x71,
0x0F, 0x00, 0x04, 0x00, 0x6E, 0x61, 0xA1, 0x24, 0xC4, 0x7E, 0x00, 0xAE,
0x41, 0xA0, 0x0A, 0x8B, 0x49, 0x2A, 0xE9, 0x68, 0xDF, 0x33, 0x1A, 0x00,
-1
};
DBG (8, "StartScan(%d,%d,%d,%d,%d,%d,%X);\n", x, y, width, height, dpi,
color, gain);
buffer = (unsigned char *) malloc (2096100);
if (buffer == NULL)
{
DBG (0, "Failed to allocate 2096100 bytes... (%s:%d)\n", __FILE__,
__LINE__);
return (0);
}
/* 1600P have a different CCD command block */
if (sanei_umax_pp_getastra () == 1600)
{
opsc04[0] = 0x19;
opsc04[1] = 0xD5;
opsc04[4] = 0x1B;
opsc04[7] = 0x70;
opscan[29] = 0x1A;
opscan[30] = 0xEE;
opsc35[29] = 0x1A;
opsc35[30] = 0xEE;
opsc53[13] = 0x03; /* may be blur filter */
}
/* get scanner status */
if (DBG_LEVEL > 8)
{
char str[64];
CMDGET (0x02, 16, state);
for (i = 0; i < 16; i++)
sprintf (str + 3 * i, "%02X ", state[i]);
str[48] = 0x00;
DBG (8, "SCANNER STATE=%s\n", str);
}
dest = (int *) malloc (65536 * 4);
if (sanei_umax_pp_getastra () != 1600)
{
CMDSETGET (0x08, 36, opsc35);
CMDSYNC (0xC2);
if (dest == NULL)
{
DBG (0, "%s:%d failed to allocate 256 Ko !\n", __FILE__, __LINE__);
return (0);
}
/* init some buffer : default calibration data ? */
dest[0] = 0x00;
dest[1] = 0x00;
dest[2] = 0x00;
for (i = 0; i < 768; i++)
dest[i + 3] = i % 256;
dest[768 + 3] = 0xAA;
dest[768 + 4] = 0xAA;
dest[768 + 5] = -1;
CMDSETGET (0x04, 768 + 5, dest);
/* check buffer returned */
for (i = 0; i < 768; i++)
{
if (dest[i + 3] != (i % 256))
{
DBG
(0,
"Error data altered: byte %d=0x%02X, should be 0x%02X ! (%s:%d)\n",
i, dest[i + 3], i % 256, __FILE__, __LINE__);
err = 1;
}
}
if (err)
return (0);
}
/* new part of buffer ... */
for (i = 0; i < 256; i++)
{
dest[i * 2] = i;
dest[i * 2 + 1] = 0x00;
}
CMDSETGET (0x08, 36, opsc35);
CMDSYNC (0xC2);
CMDSET (0x04, 512, dest);
/* another new part ... */
for (i = 0; i < 256; i++)
{
dest[i * 2] = i;
dest[i * 2 + 1] = 0x04; /* instead of 0x00 */
}
opsc35[2] = 0x06; /* instead of 0x04, write flag ? */
CMDSETGET (0x08, 36, opsc35);
CMDSYNC (0xC2);
CMDSET (0x04, 512, dest);
opsc35[2] = 0x04; /* return to initial value, read flag? */
CMDSETGET (0x08, 36, opsc35);
CMDGET (0x04, 512, dest);
/* check buffer returned */
/* if 0x4 are still 0x0 (hum..), we got a 1220P, else it is a 2000P */
for (i = 0; i < 256; i++)
{
if ((dest[2 * i] != i)
|| ((dest[2 * i + 1] != 0x04) && (dest[2 * i + 1] != 0x00)))
{
DBG
(0,
"Error data altered: expected %d=(0x%02X,0x04), found (0x%02X,0x%02X) ! (%s:%d)\n",
i, i, dest[i * 2], dest[i * 2 + 1], __FILE__, __LINE__);
err = 1;
}
}
if (err)
return (0);
/* find and move to zero */
if (MoveToOrigin () == 0)
{
DBG (0, "MoveToOrign() failed ... (%s:%d)\n", __FILE__, __LINE__);
}
else
{
DBG (16, "MoveToOrign() passed ... (%s:%d)\n", __FILE__, __LINE__);
}
/* 1600P have a different CCD command block */
if (sanei_umax_pp_getastra () == 1600)
{
opsc04[0] = 0x19;
opsc04[1] = 0xD5;
opsc04[4] = 0x1B;
opsc04[7] = 0x70;
opscan[29] = 0x1A;
opscan[30] = 0xEE;
opsc35[29] = 0x1A;
opsc35[30] = 0xEE;
opsc53[13] = 0x03; /* may be blur filter */
}
/* adjust gain and color offset */
/* red*256+green*16+blue */
if (gain == 0x0)
{
if (WarmUp (color, &gain) == 0)
{
DBG (0, "Warm-up failed !!! (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
}
/* x dpi is from 75 to 600 max, any modes */
if (dpi > 600)
xdpi = 600;
else
xdpi = dpi;
/* havent't yet found a way to make EPPRead32Buffer work */
/* with length not multiple of four bytes, so we enlarge */
/* width to meet this criteria ... */
if ((GetEPPMode () == 32) && (xdpi >= 600) && (width & 0x03))
{
width += (4 - (width & 0x03));
/* in case we go too far on the right */
if (x + width > 5100)
{
x = 5100 - width;
}
}
/* compute target size */
th = (height * dpi) / 600;
tw = (width * xdpi) / 600;
/* do gamma calibration */
if (GammaCalibration (color, dpi, gain, highlight, width, calibration) == 0)
{
DBG (0, "Gamma calibration failed !!! (%s:%d)\n", __FILE__, __LINE__);
return (0);
}
TRACE (16, "GammaCalibration() passed ...")
/* it is faster to move at low resolution, then scan */
/* than scan & move at high resolution */
distance = 0;
/* work around a bug which has yet to be solved */
y += 8;
/* move fast to scan target if possible */
if ((dpi > 150) && (y > 100))
{
distance = y;
/* move at 150 dpi resolution */
Move (y / 2, PRECISION_OFF, NULL);
/* keep the remainder for scan */
y = y % 4;
}
/* build final scan command */
/* round width and height */
width = (tw * 600) / xdpi;
height = (th * 600) / dpi;
ydpi = dpi;
if (color >= RGB_MODE)
{
if (dpi < 150)
ydpi = 150;
}
else
{
if (dpi < 300)
ydpi = 300;
}
if (color >= RGB_MODE)
{
h = ((height * ydpi) / 600) + 8;
bpp = 3;
}
else
{
h = ((height * ydpi) / 600) + 4;
bpp = 1;
}
bpl = (bpp * width * xdpi) / 600;
/* sets y resolution */
switch (ydpi)
{
case 1200:
opsc53[6] = 0x60;
opsc53[8] = 0x5E;
opsc53[9] = 0x05;
opsc53[14] = opsc53[14] & 0xF0;
break;
case 600:
opsc53[6] = 0x60;
opsc53[8] = 0x2F;
opsc53[9] = 0x05;
opsc53[14] = (opsc53[14] & 0xF0) | 0x04;
break;
case 300:
opsc53[6] = 0x00;
opsc53[8] = 0x17;
opsc53[9] = 0x05;
opsc53[14] = (opsc53[14] & 0xF0) | 0x0C;
break;
case 150:
opsc53[6] = 0x00;
opsc53[8] = 0x17;
opsc53[9] = 0x07;
opsc53[14] = (opsc53[14] & 0xF0) | 0x0C;
break;
}
/* channels gain */
opsc53[10] = gain / 16;
opsc53[11] = ((highlight / 16) & 0xF0) | (gain % 16);
opsc53[12] = highlight % 256;
/* scan height */
opsc53[0] = h % 256;
opsc53[1] = h / 256;
/* y start -1 */
y = (y * ydpi) / 600 - 1;
if (y > 0)
{
opsc53[1] |= (y % 4) * 64;
opsc53[2] = (y / 4) % 256;
opsc53[3] = 0x50 | ((y >> 10) & 0x0F);
}
else
{
opsc53[2] = 0x00;
opsc53[3] = 0x50;
}
/* x start -1 */
opscan[17] = (x - 1) % 256;
opscan[18] = (((x - 1) / 256) & 0x0F);
opscan[33] = 0x33;
if (x - 1 > 0x1000)
opscan[33] |= 0x40;
/* x end */
opscan[18] |= (((x + width) % 16) * 16);
opscan[19] = ((x + width) / 16) % 256;
if (x + width > 0x1000)
opscan[33] |= 0x80;
/* bytes per line */
opscan[24] = 0x41 + (bpl & 0x1FFF) / 256;
opscan[23] = bpl % 256;
if (color >= RGB_MODE)
{
opsc53[6] = 0x00;
opsc53[7] = 0x2F;
opsc04[6] = 0x8F;
if (sanei_umax_pp_getastra () == 1600)
{
opsc04[7] = 0x70;
opsc53[13] = 0x03;
}
else
{
opsc04[7] = 0xA0;
opsc53[13] = 0x09;
}
}
else
{
opsc53[6] = 0x60;
opsc53[7] = 0x40;
opsc53[13] = 0xC0;
opsc04[6] = 0x80 | ((gain / 16) & 0x0F);
if (sanei_umax_pp_getastra () == 1600)
{
opsc04[7] = 0x20;
opsc53[13] = 0xC3;
}
else
{
opsc04[7] = 0xA0;
opsc53[13] = 0xC9;
}
}
CMDSYNC (0x00);
/*opsc53[13] = 0x80; B&W bit */
/*opsc53[13] = 0x40; green bit */
/*opsc53[13] = 0x20; red bit */
/*opsc53[13] = 0x10; blue bit */
/* with cmd 01, may be use to do 3 pass scanning ? */
/* bits 0 to 3 seem related to sharpness */
CMDSETGET (2, 0x10, opsc53);
CMDSETGET (8, 0x24, opscan);
CMDSETGET (1, 0x08, opsc04);
CMDSYNC (0xC2);
CMDSET (4, 0x3EC6, calibration);
COMPLETIONWAIT;
*rbpp = bpp;
*rtw = tw;
*rth = th;
free (buffer);
return (1);
}
/*
* Check the scanner model. Return 1220 for
* a 1220P, or 2000 for a 2000P.
* and 610 for a 610P
* values less than 610 are errors
*/
int
sanei_umax_pp_CheckModel (void)
{
int *dest = NULL;
int state[16];
int err = 0;
int i;
int opsc35[37] =
{ 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x00, 0x03, 0xC1, 0x80,
0x00, 0x00, 0x04, 0x00, 0x16, 0x41, 0xE0, 0xAC, 0x03, 0x03, 0x00, 0x00,
0x46, 0xA0, 0x00, 0x8B, 0x49, 0x2A, 0xE9, 0x68, 0xDF, 0x13, 0x1A, 0x00,
-1
};
/* if we have already detected a scanner different from */
/* default type, no need to check again */
if (sanei_umax_pp_getastra () != 1220)
return sanei_umax_pp_getastra ();
/* get scanner status */
CMDGET (0x02, 16, state);
CMDSETGET (0x08, 36, opsc35);
CMDSYNC (0xC2);
dest = (int *) malloc (65536 * 4);
if (dest == NULL)
{
DBG (0, "%s:%d failed to allocate 256 Ko !\n", __FILE__, __LINE__);
return (0);
}
/* init some buffer : default calibration data ? */
dest[0] = 0x00;
dest[1] = 0x00;
dest[2] = 0x00;
for (i = 0; i < 768; i++)
dest[i + 3] = i % 256;
dest[768 + 3] = 0xAA;
dest[768 + 4] = 0xAA;
dest[768 + 5] = -1;
CMDSETGET (0x04, 768 + 5, dest);
/* check buffer returned */
for (i = 0; i < 768; i++)
{
if (dest[i + 3] != (i % 256))
{
DBG
(0,
"Error data altered: byte %d=0x%02X, should be 0x%02X ! (%s:%d)\n",
i, dest[i + 3], i % 256, __FILE__, __LINE__);
err = 1;
}
}
if (err)
return (0);
/* new part of buffer ... */
for (i = 0; i < 256; i++)
{
dest[i * 2] = i;
dest[i * 2 + 1] = 0x00;
}
CMDSETGET (0x08, 36, opsc35);
CMDSYNC (0xC2);
CMDSET (0x04, 512, dest);
/* another new part ... */
for (i = 0; i < 256; i++)
{
dest[i * 2] = i;
dest[i * 2 + 1] = 0x04; /* instead of 0x00 */
}
opsc35[2] = 0x06; /* instead of 0x04, write flag ? */
CMDSETGET (0x08, 36, opsc35);
CMDSYNC (0xC2);
CMDSET (0x04, 512, dest);
opsc35[2] = 0x04; /* return to initial value, read flag? */
CMDSETGET (0x08, 36, opsc35);
CMDGET (0x04, 512, dest);
/* check buffer returned */
/* if 0x4 are still 0x04, we got a 1220P, else it is a 2000P */
for (i = 0; i < 256; i++)
{
if ((dest[2 * i] != i)
|| ((dest[2 * i + 1] != 0x04) && (dest[2 * i + 1] != 0x00)))
{
DBG
(0,
"Error data altered: expected %d=(0x%02X,0x04), found (0x%02X,0x%02X) ! (%s:%d)\n",
i, i, dest[i * 2], dest[i * 2 + 1], __FILE__, __LINE__);
err = 0;
}
}
/* if buffer unchanged, we have a 1600P, or a 1220P */
/* if data has turned into 0, we have a 2000P */
if (dest[1] == 0x00)
{
sanei_umax_pp_setastra (2000);
err = 2000;
}
else
{
/* detects 1600 by finding black scans */
MoveToOrigin ();
err = sanei_umax_pp_getastra ();
/* parking */
CMDSYNC (0xC2);
CMDSYNC (0x00);
if (sanei_umax_pp_Park () == 0)
DBG (0, "Park failed !!! (%s:%d)\n", __FILE__, __LINE__);
/* poll parking */
do
{
sleep (1);
CMDSYNC (0x40);
}
while ((sanei_umax_pp_ScannerStatus () & MOTOR_BIT) == 0x00);
}
/* return guessed model number */
CMDSYNC (0x00);
return (err);
}
/* sets, resets gamma tables */
void
sanei_umax_pp_gamma (int *red, int *green, int *blue)
{
if (red != NULL)
{
ggRed = red;
}
else
{
ggRed = ggamma;
}
if (green != NULL)
{
ggGreen = green;
}
else
{
ggGreen = ggamma;
}
if (blue != NULL)
{
ggBlue = blue;
}
else
{
ggBlue = ggamma;
}
}