kopia lustrzana https://gitlab.com/sane-project/backends
1456 wiersze
36 KiB
C
1456 wiersze
36 KiB
C
/* sane - Scanner Access Now Easy.
|
|
Copyright (C) 2003 Martijn van Oosterhout <kleptog@svana.org>
|
|
Copyright (C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
|
|
Copyright (c) 2003 Henning Meier-Geinitz, <henning@meier-geinitz.de>
|
|
|
|
Originally copied from HP3300 testtools. Original notice follows:
|
|
|
|
Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl)
|
|
|
|
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.
|
|
|
|
HP5400/5470 Test util.
|
|
Currently is only able to read back the scanner version string,
|
|
but this basically demonstrates ability to communicate with the scanner.
|
|
|
|
Massively expanded. Can do calibration scan, upload gamma and calibration
|
|
tables and stores the results of a scan. - 19/02/2003 Martijn
|
|
*/
|
|
|
|
#include <stdio.h> /* for printf */
|
|
#include <stdlib.h> /* for exit */
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <math.h>
|
|
#include <netinet/in.h> /* for htons */
|
|
#include <string.h>
|
|
|
|
|
|
#include "hp5400.h"
|
|
#include "hp5400_xfer.h"
|
|
#include "hp5400_internal.h"
|
|
#include "hp5400_debug.h" /* debug functions */
|
|
|
|
|
|
#ifndef min
|
|
#define min(A,B) (((A)<(B)) ? (A) : (B))
|
|
#endif
|
|
#ifndef max
|
|
#define max(A,B) (((A)>(B)) ? (A) : (B))
|
|
#endif
|
|
|
|
|
|
#ifndef STRING_VERSION_MATCH
|
|
#define NO_STRING_VERSION_MATCH 1
|
|
#endif
|
|
|
|
#ifdef __GNUC__
|
|
#define PACKED __attribute__ ((packed))
|
|
#else
|
|
#define PACKED
|
|
#endif
|
|
|
|
/* If this is enabled, a copy of the raw data from the scanner will be saved to
|
|
imagedebug.dat and the attempted conversion to imagedebug.ppm */
|
|
/* #define IMAGE_DEBUG */
|
|
|
|
/* If this is defined you get extra info on the calibration */
|
|
/* #define CALIB_DEBUG */
|
|
|
|
|
|
typedef struct versionString {
|
|
char strVersion[128];
|
|
} versionString;
|
|
|
|
const int numVersions = 3;
|
|
versionString *MatchVersions;
|
|
|
|
|
|
static TScannerModel Model_HP54xx =
|
|
{ "Hewlett-Packard", "HP54xx Flatbed Scanner" };
|
|
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
InitHp5400_internal() {
|
|
|
|
MatchVersions = malloc( sizeof(versionString) * numVersions );
|
|
strcpy( MatchVersions[0].strVersion, "SilitekIBlizd C3 ScannerV0.84");
|
|
strcpy( MatchVersions[1].strVersion, "SilitekIBlizd C3 ScannerV0.86");
|
|
strcpy( MatchVersions[2].strVersion, "SilitekIBlizd C3 ScannerV0.87");
|
|
|
|
return 1;
|
|
}
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
FreeHp5400_internal() {
|
|
|
|
free(MatchVersions);
|
|
MatchVersions = NULL;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
WriteByte (int iHandle, int cmd, char data)
|
|
{
|
|
if (hp5400_command_write (iHandle, cmd, 1, &data) < 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to send byte (cmd=%04X)\n", cmd);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
SetLamp (THWParams * pHWParams, int fLampOn)
|
|
{
|
|
if (fLampOn)
|
|
{
|
|
if (WriteByte (pHWParams->iXferHandle, 0x0000, 0x01) == 0)
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
WarmupLamp (int iHandle)
|
|
{
|
|
int i = 30; /* Max 30 seconds, 15 is typical for cold start? */
|
|
int couldRead;
|
|
unsigned char dataVerify[0x02];
|
|
|
|
/* Keep writing 01 to 0000 until no error... */
|
|
unsigned char data0000[] = {
|
|
0x01
|
|
};
|
|
unsigned char data0300[3];
|
|
|
|
|
|
hp5400_command_write_noverify (iHandle, 0x0000, data0000, 1);
|
|
|
|
do
|
|
{
|
|
hp5400_command_read_noverify (iHandle, 0x0300, 3, data0300);
|
|
|
|
hp5400_command_write_noverify (iHandle, 0x0000, data0000, 1);
|
|
|
|
couldRead =
|
|
hp5400_command_read_noverify (iHandle, 0xc500, 0x02, dataVerify);
|
|
if ((dataVerify[0] != 0) || (dataVerify[1] != 0))
|
|
sleep (1);
|
|
}
|
|
while ((i-- > 0) && (couldRead >= 0)
|
|
&& ((dataVerify[0] != 0) || (dataVerify[1] != 0)));
|
|
|
|
if (i > 0)
|
|
return 0;
|
|
|
|
/*
|
|
|
|
while( i > 0 )
|
|
{
|
|
if( WriteByte( iHandle, 0x0000, 0x01 ) == 0 )
|
|
return 0;
|
|
sleep(1);
|
|
i--;
|
|
}
|
|
*/
|
|
|
|
HP5400_DBG (DBG_MSG, "***WARNING*** Warmup lamp failed...\n");
|
|
return -1;
|
|
}
|
|
|
|
#define CALPIXBYBLOCK 42
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
SetCalibration (int iHandle, int numPixels, unsigned int *low_vals[3],
|
|
unsigned int *high_vals[3], int dpi)
|
|
{
|
|
char cmd[8];
|
|
/* unsigned char cmd[8]; */ /* should fix the compilation warning
|
|
but I don't have a scanner right now
|
|
to check that the fix does not break
|
|
calibration */
|
|
|
|
int i, j, k;
|
|
struct CalPixel
|
|
{
|
|
char highr[2], highg[2], highb[2];
|
|
char lowr[2], lowg[2], lowb[2];
|
|
};
|
|
struct CalBlock
|
|
{
|
|
struct CalPixel pixels[CALPIXBYBLOCK];
|
|
char pad[8];
|
|
}
|
|
PACKED;
|
|
|
|
struct CalBlock *calinfo;
|
|
|
|
/**
|
|
we did scan test at 300 dpi, so we don't have all the needed pixels.
|
|
To fill the gap, we loop
|
|
*/
|
|
int numLoop = max (1, dpi / 300);
|
|
int calBlockSize = CALPIXBYBLOCK * (6 * sizeof (short)) + 8 * sizeof (char); /* = sizeof(calBlock) */
|
|
int numCalBlock =
|
|
((numPixels / CALPIXBYBLOCK) +
|
|
((numPixels % CALPIXBYBLOCK != 0) ? 1 : 0));
|
|
int calSize = numLoop * calBlockSize * numCalBlock;
|
|
|
|
calinfo = malloc (calSize);
|
|
memset (calinfo, 0, calSize);
|
|
|
|
for (j = 0; j < numLoop * numCalBlock * CALPIXBYBLOCK; j++)
|
|
{
|
|
struct CalPixel *pixel =
|
|
&calinfo[j / CALPIXBYBLOCK].pixels[j % CALPIXBYBLOCK];
|
|
|
|
/*
|
|
i = ( j % (int)( 0.80 * numPixels ) ) + (int)(0.10 * numPixels );
|
|
*/
|
|
/* better solution : stretch the actual scan size to the calibration size */
|
|
i = j / numLoop;
|
|
|
|
/* This is obviously not quite right. The values on
|
|
* the right are approximatly what windows sends */
|
|
k = (high_vals[0][i] > 0x4000) ? 1000000000 / high_vals[0][i] : 0; /* 0x6700 */
|
|
pixel->highr[0] = k;
|
|
pixel->highr[1] = k >> 8;
|
|
k = (high_vals[1][i] > 0x4000) ? 1000000000 / high_vals[1][i] : 0; /* 0x5e00 */
|
|
pixel->highg[0] = k;
|
|
pixel->highg[1] = k >> 8;
|
|
k = (high_vals[2][i] > 0x4000) ? 1000000000 / high_vals[2][i] : 0; /* 0x6000 */
|
|
pixel->highb[0] = k;
|
|
pixel->highb[1] = k >> 8;
|
|
|
|
pixel->lowr[0] = low_vals[0][i]; /* 0x0530 */
|
|
pixel->lowr[1] = low_vals[0][i] >> 8;
|
|
pixel->lowg[0] = low_vals[1][i]; /* 0x0530 */
|
|
pixel->lowg[1] = low_vals[1][i] >> 8;
|
|
pixel->lowb[0] = low_vals[2][i]; /* 0x0530 */
|
|
pixel->lowb[1] = low_vals[2][i] >> 8;
|
|
}
|
|
|
|
cmd[0] = 0xff & (calSize >> 16);
|
|
cmd[1] = 0xff & (calSize >> 8);
|
|
cmd[2] = 0xff & (calSize >> 0);
|
|
cmd[3] = 0x00;
|
|
cmd[4] = 0x54;
|
|
cmd[5] = 0x02;
|
|
cmd[6] = 0x80;
|
|
cmd[7] = 0x00;
|
|
|
|
hp5400_bulk_command_write (iHandle, 0xE603, cmd, 8, calSize, calSize,
|
|
(void *) calinfo);
|
|
|
|
free (calinfo);
|
|
return 0;
|
|
}
|
|
|
|
/* Write a gamma table */
|
|
HP5400_SANE_STATIC
|
|
void
|
|
WriteGammaCalibTable (int iHandle, const int *pabGammaR, const int *pabGammaG,
|
|
const int *pabGammaB)
|
|
{
|
|
char cmd[3];
|
|
char *buffer;
|
|
int i, j;
|
|
|
|
/* Setup dummy gamma correction table */
|
|
buffer = malloc (2 * 65536);
|
|
|
|
cmd[0] = 2;
|
|
cmd[1] = 0;
|
|
cmd[2] = 0;
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
const int *ptr = (i == 0) ? pabGammaR :
|
|
(i == 1) ? pabGammaG : pabGammaB;
|
|
|
|
for (j = 0; j < 65536; j++) {
|
|
buffer[2 * j] = ptr[j];
|
|
buffer[2 * j + 1] = ptr[j] >> 8;
|
|
}
|
|
|
|
hp5400_bulk_command_write (iHandle, 0x2A01 + i, cmd, 3, 2 * 65536,
|
|
65536, (void *) buffer);
|
|
}
|
|
free (buffer);
|
|
|
|
return;
|
|
}
|
|
|
|
#ifdef STANDALONE
|
|
HP5400_SANE_STATIC
|
|
void
|
|
SetDefaultGamma (int iHandle)
|
|
{
|
|
int *buffer = malloc (sizeof (int) * 65536);
|
|
int i;
|
|
|
|
for (i = 0; i < 65336; i++)
|
|
buffer[i] = i;
|
|
|
|
WriteGammaCalibTable (iHandle, buffer, buffer, buffer);
|
|
}
|
|
#endif
|
|
|
|
#define BUFFER_SIZE (6*65536)
|
|
|
|
#ifdef IMAGE_DEBUG
|
|
FILE *temp;
|
|
#endif
|
|
|
|
/* Bytes per line is the number of pixels. The actual bytes is one more */
|
|
HP5400_SANE_STATIC
|
|
void
|
|
CircBufferInit (int iHandle, TDataPipe * p, int iBytesPerLine,
|
|
int bpp, int iMisAlignment, int blksize, int iTransferSize)
|
|
{
|
|
iHandle = iHandle; /* to avoid compilation warning */
|
|
p->buffersize = max (BUFFER_SIZE, 3 * blksize);
|
|
|
|
if (p->buffer)
|
|
{
|
|
free (p->buffer);
|
|
}
|
|
|
|
/* Allocate a large enough buffer for transfer */
|
|
p->buffer = malloc (p->buffersize);
|
|
|
|
p->pixels = (iBytesPerLine / 3) / bpp;
|
|
|
|
/* These three must always be positive */
|
|
p->roff = 0;
|
|
p->goff = p->pixels * bpp + 1;
|
|
p->boff = 2 * p->pixels * bpp + 2;;
|
|
|
|
p->linelength = iBytesPerLine + 3; /* NUL at end of each row */
|
|
p->bpp = bpp;
|
|
p->bufstart = p->bufend = 0;
|
|
|
|
if (iMisAlignment > 0)
|
|
{
|
|
p->roff += 0;
|
|
p->goff += p->linelength * iMisAlignment;
|
|
p->boff += p->linelength * iMisAlignment * 2;
|
|
}
|
|
|
|
if (iMisAlignment < 0)
|
|
{
|
|
p->roff -= p->linelength * iMisAlignment * 2;
|
|
p->goff -= p->linelength * iMisAlignment;
|
|
p->boff -= 0;
|
|
}
|
|
|
|
p->blksize = blksize;
|
|
p->transfersize = iTransferSize;
|
|
|
|
#ifdef IMAGE_DEBUG
|
|
temp = fopen ("imagedebug.dat", "w+b");
|
|
#endif
|
|
|
|
HP5400_DBG (DBG_MSG,
|
|
"Begin: line=%d (%X), pixels=%d (%X), r=%d (%X), g=%d (%X), b=%d (%X), bpp=%d, step=%d\n",
|
|
p->linelength, p->linelength, p->pixels, p->pixels, p->roff, p->roff,
|
|
p->goff, p->goff, p->boff, p->boff, bpp, iMisAlignment);
|
|
}
|
|
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
CircBufferGetLine (int iHandle, TDataPipe * p, void *pabLine)
|
|
{
|
|
int i;
|
|
int maxoff = 0;
|
|
char* buftmp = (char*) (p->buffer);
|
|
|
|
/* HP5400_DBG(DBG_MSG, "CircBufferGetLine:\n"); */
|
|
|
|
if (p->roff > maxoff)
|
|
maxoff = p->roff;
|
|
if (p->goff > maxoff)
|
|
maxoff = p->goff;
|
|
if (p->boff > maxoff)
|
|
maxoff = p->boff;
|
|
|
|
maxoff += p->pixels * p->bpp;
|
|
|
|
if (maxoff < p->linelength)
|
|
maxoff = p->linelength;
|
|
|
|
|
|
/* resize buffer if needed */
|
|
if (p->bufstart + maxoff >= p->buffersize + p->blksize)
|
|
{
|
|
/* store actual buffer pointer */
|
|
void *tmpBuf = p->buffer;
|
|
/* calculate new size for buffer (oversize a bit) */
|
|
int newsize = p->bufstart + maxoff + 2 * p->blksize;
|
|
|
|
p->buffer = malloc (newsize);
|
|
memcpy (p->buffer, tmpBuf, p->buffersize);
|
|
p->buffersize = newsize;
|
|
|
|
/* free old buffer */
|
|
free (tmpBuf);
|
|
buftmp = (char*)(p->buffer);
|
|
}
|
|
|
|
while (p->bufstart + maxoff >= p->bufend) /* Not enough data in buffer */
|
|
{
|
|
int res;
|
|
unsigned char cmd[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
cmd[4] = p->blksize;
|
|
cmd[5] = p->blksize >> 8;
|
|
|
|
assert ((p->bufend + p->blksize) <= p->buffersize);
|
|
|
|
HP5400_DBG (DBG_MSG, "Reading block, %d bytes remain\n", p->transfersize);
|
|
p->transfersize -= p->blksize;
|
|
|
|
res =
|
|
hp5400_bulk_read_block (iHandle, CMD_INITBULK3, cmd, sizeof (cmd),
|
|
buftmp + p->bufend, p->blksize);
|
|
if (res != p->blksize)
|
|
{
|
|
HP5400_DBG (DBG_ERR, "*** ERROR: Read returned %d. FATAL.\n", res);
|
|
return -1;
|
|
}
|
|
#ifdef IMAGE_DEBUG
|
|
fwrite (
|
|
buftmp + p->bufend
|
|
,p->blksize
|
|
,1
|
|
,temp
|
|
);
|
|
#endif
|
|
p->bufend += p->blksize;
|
|
}
|
|
|
|
assert (p->bufstart + maxoff < p->bufend);
|
|
|
|
/* Copy a line into the result buffer */
|
|
if (p->bpp == 1)
|
|
{
|
|
char *itPix = (char *) pabLine;
|
|
char *itR = (char *) (buftmp + p->bufstart + p->roff);
|
|
char *itG = (char *) (buftmp + p->bufstart + p->goff);
|
|
char *itB = (char *) (buftmp + p->bufstart + p->boff);
|
|
for (i = 0; i < p->pixels; i++)
|
|
{
|
|
/* pointer move goes a little bit faster than vector access */
|
|
/* Although I wouldn't be surprised if the compiler worked that out anyway.
|
|
* No matter, this is easier to read :) */
|
|
*(itPix++) = *(itR++);
|
|
*(itPix++) = *(itG++);
|
|
*(itPix++) = *(itB++);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
short *itPix = (short *) pabLine;
|
|
short *itR = (short *) (buftmp + p->bufstart + p->roff);
|
|
short *itG = (short *) (buftmp + p->bufstart + p->goff);
|
|
short *itB = (short *) (buftmp + p->bufstart + p->boff);
|
|
for (i = 0; i < p->pixels; i++)
|
|
{
|
|
#if 0
|
|
/* This code, while correct for PBM is not correct for the host and
|
|
* since we need it correct for calibration, it has to go */
|
|
((short *) pabLine)[3 * i + 0] =
|
|
*((short *) (p->buffer + p->bufstart + p->roff + 2 * i));
|
|
((short *) pabLine)[3 * i + 1] =
|
|
*((short *) (p->buffer + p->bufstart + p->goff + 2 * i));
|
|
((short *) pabLine)[3 * i + 2] =
|
|
*((short *) (p->buffer + p->bufstart + p->boff + 2 * i));
|
|
#else
|
|
/* pointer move goes a little bit faster than vector access */
|
|
*(itPix++) = htons (*(itR++));
|
|
*(itPix++) = htons (*(itG++));
|
|
*(itPix++) = htons (*(itB++));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
p->bufstart += p->linelength;
|
|
|
|
assert (p->bufstart <= p->bufend);
|
|
|
|
/* If we've used a whole block at the beginning, move it */
|
|
if (p->bufstart > p->blksize)
|
|
{
|
|
memmove (
|
|
buftmp
|
|
,buftmp + p->bufstart
|
|
,p->bufend - p->bufstart
|
|
);
|
|
|
|
p->bufend -= p->bufstart;
|
|
p->bufstart = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
HP5400_SANE_STATIC
|
|
void
|
|
CircBufferExit (TDataPipe * p)
|
|
{
|
|
free (p->buffer);
|
|
p->buffer = NULL;
|
|
#ifdef IMAGE_DEBUG
|
|
fclose (temp);
|
|
temp = NULL;
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef STANDALONE
|
|
/* bpp is BYTES per pixel */
|
|
HP5400_SANE_STATIC
|
|
void
|
|
DecodeImage (FILE * file, int planes, int bpp, int xsize, int ysize,
|
|
const char *filename)
|
|
{
|
|
char *in, *buf;
|
|
char *p[3];
|
|
FILE *output;
|
|
int i, j, k;
|
|
|
|
/* xsize is byte width, not pixel width */
|
|
xsize /= planes * bpp;
|
|
|
|
HP5400_DBG (DBG_MSG,
|
|
"DecodeImage(planes=%d,bpp=%d,xsize=%d,ysize=%d) => %d (file=%s)\n",
|
|
planes, bpp, xsize, ysize, planes * bpp * xsize * ysize, filename);
|
|
|
|
in = malloc (planes * (xsize * bpp + 1));
|
|
|
|
for (i = 0; i < planes; i++)
|
|
p[i] = in + i * (xsize * bpp + 1);
|
|
|
|
buf = malloc (3 * xsize * bpp);
|
|
|
|
output = fopen (filename, "wb");
|
|
|
|
fprintf (output, "P%d\n%d %d\n", (planes == 3) ? 6 : 5, xsize, ysize);
|
|
fprintf (output, "%d\n", (bpp == 1) ? 255 : 0xb000);
|
|
|
|
for (i = 0; i < ysize; i++)
|
|
{
|
|
fread (in, planes * (xsize * bpp + 1), 1, file);
|
|
|
|
for (j = 0; j < xsize; j++)
|
|
{
|
|
for (k = 0; k < planes; k++)
|
|
{
|
|
if (bpp == 1)
|
|
{
|
|
buf[j * planes + k] = p[k][j];
|
|
}
|
|
else if (bpp == 2)
|
|
{
|
|
buf[j * planes * 2 + k * 2 + 0] = p[k][2 * j + 0];
|
|
buf[j * planes * 2 + k * 2 + 1] = p[k][2 * j + 1];
|
|
}
|
|
}
|
|
}
|
|
fwrite (buf, planes * xsize * bpp, 1, output);
|
|
}
|
|
|
|
fclose (output);
|
|
|
|
free (in);
|
|
free (buf);
|
|
}
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
hp5400_test_scan_response (struct ScanResponse *resp, struct ScanRequest *req)
|
|
{
|
|
req = req; /* to avoid compilation warning */
|
|
HP5400_DBG (DBG_MSG, "Scan response:\n");
|
|
HP5400_DBG (DBG_MSG, " transfersize=%d htonl-> %d\n", resp->transfersize,
|
|
htonl (resp->transfersize));
|
|
HP5400_DBG (DBG_MSG, " xsize=%d htonl-> %d\n", resp->xsize,
|
|
htonl (resp->xsize));
|
|
HP5400_DBG (DBG_MSG, " ysize=%d htons-> %d\n", resp->ysize,
|
|
htons (resp->ysize));
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
/* This is a very specialised scanning function. It does the scan request as
|
|
* usual but instead of producing an image it returns three arrays of ints.
|
|
* These are averages of the R,G,B values for each column.
|
|
*
|
|
* Note the array argument should point to an array of three NULL. These
|
|
* will be overwritten with allocated pointers. */
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
DoAverageScan (int iHandle, struct ScanRequest *req, int code,
|
|
unsigned int **array)
|
|
{
|
|
THWParams HWParams;
|
|
struct ScanResponse res;
|
|
unsigned short *buffer;
|
|
int i, j, k, length;
|
|
|
|
memset (&HWParams, 0, sizeof (HWParams));
|
|
|
|
HWParams.iXferHandle = iHandle;
|
|
|
|
if (InitScan2 (SCAN_TYPE_CALIBRATION, req, &HWParams, &res, 0, code) != 0)
|
|
return -1; /* No colour offseting, we want raw */
|
|
|
|
length = htonl (res.xsize) / 6;
|
|
|
|
HP5400_DBG (DBG_MSG, "Calibration scan: %d pixels wide\n", length);
|
|
|
|
for (j = 0; j < 3; j++)
|
|
{
|
|
array[j] = malloc (sizeof (int) * length);
|
|
memset (array[j], 0, sizeof (int) * length); /* Clear array */
|
|
}
|
|
|
|
buffer = malloc (htonl (res.xsize) + 1);
|
|
|
|
/* First we just sum them all */
|
|
for (i = 0; i < htons (res.ysize); i++)
|
|
{
|
|
CircBufferGetLine (iHandle, &HWParams.pipe, buffer);
|
|
|
|
for (j = 0; j < length; j++)
|
|
for (k = 0; k < 3; k++)
|
|
array[k][j] += buffer[3 * j + k];
|
|
}
|
|
|
|
free (buffer);
|
|
FinishScan (&HWParams);
|
|
|
|
/* Now divide by the height to get the average */
|
|
for (j = 0; j < length; j++)
|
|
for (k = 0; k < 3; k++)
|
|
array[k][j] /= htons (res.ysize);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef STANDALONE
|
|
HP5400_SANE_STATIC
|
|
int
|
|
DoScan (int iHandle, struct ScanRequest *req, const char *filename, int code,
|
|
struct ScanResponse *res)
|
|
{
|
|
FILE *file;
|
|
THWParams HWParams;
|
|
struct ScanResponse res_temp;
|
|
void *buffer;
|
|
/* int bpp, planes; */
|
|
int i;
|
|
|
|
code = code; /*to avoid compilation warning*/
|
|
|
|
if (res == NULL)
|
|
res = &res_temp;
|
|
|
|
memset (&HWParams, 0, sizeof (HWParams));
|
|
|
|
file = fopen (filename, "w+b");
|
|
if (!file)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "Couldn't open outputfile (%s)\n", strerror (errno));
|
|
return -1;
|
|
}
|
|
|
|
HWParams.iXferHandle = iHandle;
|
|
|
|
if (InitScan2 (SCAN_TYPE_NORMAL, req, &HWParams, res, 1, 0x40) != 0)
|
|
return -1;
|
|
|
|
fprintf (file, "P%d\n%d %d\n", 6, htonl (res->xsize) / 3,
|
|
htons (res->ysize));
|
|
fprintf (file, "%d\n", 255);
|
|
|
|
buffer = malloc (htonl (res->xsize) + 1);
|
|
for (i = 0; i < htons (res->ysize); i++)
|
|
{
|
|
CircBufferGetLine (iHandle, &HWParams.pipe, buffer);
|
|
|
|
fwrite (buffer, htonl (res->xsize), 1, file);
|
|
}
|
|
free (buffer);
|
|
|
|
FinishScan (&HWParams);
|
|
|
|
fclose (file);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
Calibrate (int iHandle, int dpi)
|
|
{
|
|
struct ScanRequest req;
|
|
|
|
unsigned int *low_array[3];
|
|
unsigned int *high_array[3];
|
|
#ifdef CALIB_DEBUG
|
|
char buffer[512];
|
|
int i, j;
|
|
#endif
|
|
|
|
/* The first calibration scan. Finds maximum of each CCD */
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
req.x1 = 0x08;
|
|
req.dpix = htons (300); /* = 300 dpi */
|
|
req.dpiy = htons (300); /* = 300 dpi */
|
|
req.offx = htons (0); /* = 0cm */
|
|
req.offy = htons (0); /* = 0cm */
|
|
req.lenx = htons (2690); /* = 22.78cm */
|
|
req.leny = htons (50); /* = 0.42cm */
|
|
|
|
req.flags1 = htons (0x0000);
|
|
req.flags2 = htons (0x0010);
|
|
req.flags3 = htons (0x3020); /* First calibration scan, 48bpp */
|
|
|
|
req.gamma[0] = htons (100);
|
|
req.gamma[1] = htons (100);
|
|
req.gamma[2] = htons (100);
|
|
|
|
if (DoAverageScan (iHandle, &req, 0x40, high_array) != 0)
|
|
return -1;
|
|
|
|
#ifdef CALIB_DEBUG
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
int len;
|
|
buffer[0] = 0;
|
|
sprintf (buffer, "Average %d: \n", i);
|
|
len = strlen (buffer);
|
|
|
|
for (j = 0; j < 24; j++)
|
|
{
|
|
sprintf (buffer + len, "%04X ", high_array[i][j]);
|
|
len += 5;
|
|
}
|
|
strcat (buffer, " ... \n");
|
|
len += 6;
|
|
|
|
for (j = 1000; j < 1024; j++)
|
|
{
|
|
sprintf (buffer + len, "%04X ", high_array[i][j]);
|
|
len += 5;
|
|
}
|
|
strcat (buffer, " ... \n");
|
|
len += 6;
|
|
|
|
for (j = 2000; j < 2024; j++)
|
|
{
|
|
sprintf (buffer + len, "%04X ", high_array[i][j]);
|
|
len += 5;
|
|
}
|
|
strcat (buffer, " ... \n");
|
|
len += 6;
|
|
|
|
HP5400_DBG (DBG_MSG, buffer);
|
|
}
|
|
#endif
|
|
|
|
/* The second calibration scan. Finds minimum of each CCD */
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
req.x1 = 0x08;
|
|
req.dpix = htons (300); /* = 300 dpi */
|
|
req.dpiy = htons (300); /* = 300 dpi */
|
|
req.offx = htons (0); /* = 0cm */
|
|
req.offy = htons (0); /* = 0cm */
|
|
req.lenx = htons (2690); /* = 22.78cm */
|
|
req.leny = htons (16); /* = 0.14cm */
|
|
|
|
req.flags1 = htons (0x0000);
|
|
req.flags2 = htons (0x0010);
|
|
req.flags3 = htons (0x3024); /* Second calibration scan, 48bpp */
|
|
|
|
req.gamma[0] = htons (100);
|
|
req.gamma[1] = htons (100);
|
|
req.gamma[2] = htons (100);
|
|
|
|
if (DoAverageScan (iHandle, &req, 0x00, low_array) != 0)
|
|
return -1;
|
|
|
|
#ifdef CALIB_DEBUG
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
int len;
|
|
buffer[0] = 0;
|
|
sprintf (buffer, "Average %d: \n", i);
|
|
len = strlen (buffer);
|
|
|
|
for (j = 0; j < 24; j++)
|
|
{
|
|
sprintf (buffer + len, "%04X ", low_array[i][j]);
|
|
len += 5;
|
|
}
|
|
strcat (buffer, " ... \n");
|
|
len += 6;
|
|
|
|
for (j = 1000; j < 1024; j++)
|
|
{
|
|
sprintf (buffer + len, "%04X ", low_array[i][j]);
|
|
len += 5;
|
|
}
|
|
strcat (buffer, " ... \n");
|
|
len += 6;
|
|
|
|
for (j = 2000; j < 2024; j++)
|
|
{
|
|
sprintf (buffer + len, "%04X ", low_array[i][j]);
|
|
len += 5;
|
|
}
|
|
strcat (buffer, " ... \n");
|
|
len += 6;
|
|
|
|
HP5400_DBG (DBG_MSG, buffer);
|
|
}
|
|
#endif
|
|
|
|
SetCalibration (iHandle, 2690, low_array, high_array, dpi);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef STANDALONE
|
|
HP5400_SANE_STATIC
|
|
int
|
|
hp5400_scan (int iHandle, TScanParams * params, THWParams * pHWParams,
|
|
const char *filename)
|
|
{
|
|
struct ScanRequest req;
|
|
struct ScanResponse res;
|
|
int result;
|
|
|
|
pHWParams = pHWParams; /*to avoid compilation warning*/
|
|
|
|
HP5400_DBG (DBG_MSG, "\n");
|
|
HP5400_DBG (DBG_MSG, "Scanning :\n");
|
|
HP5400_DBG (DBG_MSG, " dpi(x) : %d\n", params->iDpi);
|
|
HP5400_DBG (DBG_MSG, " dpi(y) : %d\n", params->iLpi);
|
|
HP5400_DBG (DBG_MSG, " x0 : %d\n", params->iLeft);
|
|
HP5400_DBG (DBG_MSG, " y0 : %d\n", params->iTop);
|
|
HP5400_DBG (DBG_MSG, " width : %d\n", params->iWidth);
|
|
HP5400_DBG (DBG_MSG, " height : %d\n", params->iHeight);
|
|
HP5400_DBG (DBG_MSG, "\n");
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
req.x1 = 0x08;
|
|
req.dpix = htons (params->iDpi);
|
|
req.dpiy = htons (params->iLpi);
|
|
|
|
/* These offsets and lengths should all be in the reference DPI which
|
|
* is set to HW_LPI */
|
|
req.offx = htons (params->iLeft);
|
|
req.offy = htons (params->iTop);
|
|
req.lenx = htons (params->iWidth);
|
|
req.leny = htons (params->iHeight);
|
|
|
|
req.flags1 = htons (0x0080);
|
|
req.flags2 = htons (0x0000);
|
|
req.flags3 = htons ((params->iDpi < 2400) ? 0x18E8 : 0x18C0); /* Try preview scan */
|
|
|
|
req.gamma[0] = htons (100);
|
|
req.gamma[1] = htons (100);
|
|
req.gamma[2] = htons (100);
|
|
|
|
if (Calibrate (iHandle, params->iDpi) != 0)
|
|
return -1;
|
|
SetDefaultGamma (iHandle);
|
|
|
|
result = DoScan (iHandle, &req, filename, 0x40, &res);
|
|
|
|
/* Pass the results back to the parent */
|
|
params->iBytesPerLine = htonl (res.xsize);
|
|
params->iLines = htons (res.ysize);
|
|
|
|
#if 0
|
|
imageFile = fopen ("output.dat", "r+b");
|
|
if (imageFile)
|
|
{
|
|
int planes = 3;
|
|
int bpp = 1;
|
|
fseek (imageFile, 0, SEEK_SET);
|
|
DecodeImage (imageFile, planes, bpp, planes * bpp * params->iWidth,
|
|
params->iHeight, filename);
|
|
fclose (imageFile);
|
|
}
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
PreviewScan (int iHandle)
|
|
{
|
|
TScanParams params;
|
|
THWParams pHWParams;
|
|
|
|
/* Reference LPI is 300dpi, remember */
|
|
params.iDpi = 75;
|
|
params.iLpi = 75;
|
|
params.iLeft = 0;
|
|
params.iTop = 0;
|
|
params.iWidth = 2552; /* = 21.61cm * 300dpi */
|
|
params.iHeight = 3510; /* = 29.72cm * 300dpi */
|
|
params.iColourOffset = 1;
|
|
|
|
return hp5400_scan (iHandle, ¶ms, &pHWParams, "output.ppm");
|
|
}
|
|
|
|
|
|
static char UISetup1[] = {
|
|
/* Offset 40 */
|
|
0x50, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6E, 0x67, 0x14, 0x00,
|
|
0x52, 0x65, 0x61, 0x64,
|
|
0x79, 0x00, 0x53, 0x63, 0x61, 0x6E, 0x6E, 0x65, 0x72, 0x20, 0x4C, 0x6F,
|
|
0x63, 0x6B, 0x65, 0x64,
|
|
0x00, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x00, 0x43, 0x61, 0x6E, 0x63, 0x65,
|
|
0x6C, 0x69, 0x6E, 0x67,
|
|
0x14, 0x00, 0x50, 0x6F, 0x77, 0x65, 0x72, 0x53, 0x61, 0x76, 0x65, 0x20,
|
|
0x4F, 0x6E, 0x00, 0x53,
|
|
};
|
|
|
|
static char UISetup2[] = {
|
|
|
|
0x63, 0x61, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x14, 0x00, 0x41, 0x44, 0x46,
|
|
0x20, 0x70, 0x61, 0x70,
|
|
0x65, 0x72, 0x20, 0x6A, 0x61, 0x6D, 0x00, 0x43, 0x6F, 0x70, 0x69, 0x65,
|
|
0x73, 0x00, 0x00,
|
|
};
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
InitScanner (int iHandle)
|
|
{
|
|
WarmupLamp (iHandle);
|
|
|
|
if (WriteByte (iHandle, 0xF200, 0x40) < 0)
|
|
return -1;
|
|
|
|
if (hp5400_command_write (iHandle, 0xF10B, sizeof (UISetup1), UISetup1) < 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to send UISetup1 (%lu)\n", (u_long) sizeof (UISetup1));
|
|
return -1;
|
|
}
|
|
|
|
if (WriteByte (iHandle, 0xF200, 0x00) < 0)
|
|
return -1;
|
|
|
|
if (hp5400_command_write (iHandle, 0xF10C, sizeof (UISetup2), UISetup2) < 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to send UISetup2\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* Warning! The caller must have configured the gamma tables at this stage */
|
|
HP5400_SANE_STATIC
|
|
int
|
|
InitScan (enum ScanType scantype, TScanParams * pParams,
|
|
THWParams * pHWParams)
|
|
{
|
|
struct ScanRequest req;
|
|
struct ScanResponse res;
|
|
int ret;
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
req.x1 = 0x08;
|
|
req.dpix = htons (pParams->iDpi); /* = 300 dpi */
|
|
req.dpiy = htons (pParams->iLpi); /* = 300 dpi */
|
|
req.offx = htons (pParams->iLeft); /* = 0cm */
|
|
req.offy = htons (pParams->iTop); /* = 0cm */
|
|
req.lenx = htons (pParams->iWidth); /* = 22.78cm */
|
|
|
|
/* Scan a few extra rows so we can colour offset properly. At 300dpi the
|
|
* difference is 4 lines */
|
|
|
|
req.leny = htons (pParams->iHeight); /* = 0.42cm */
|
|
|
|
req.flags1 = htons ((scantype == SCAN_TYPE_CALIBRATION) ? 0x0000 : 0x0080);
|
|
req.flags2 = htons ((scantype == SCAN_TYPE_CALIBRATION) ? 0x0010 :
|
|
(scantype == SCAN_TYPE_PREVIEW) ? 0x0000 :
|
|
/* SCAN_TYPE_NORMAL */ 0x0040);
|
|
req.flags3 = htons (0x18E8);
|
|
|
|
req.gamma[0] = htons (100);
|
|
req.gamma[1] = htons (100);
|
|
req.gamma[2] = htons (100);
|
|
|
|
if (Calibrate (pHWParams->iXferHandle, pParams->iDpi) != 0)
|
|
return -1;
|
|
/* SetDefaultGamma( pHWParams->iXferHandle ); ** Must be done by caller */
|
|
|
|
HP5400_DBG (DBG_MSG, "Calibration complete\n");
|
|
ret =
|
|
InitScan2 (scantype, &req, pHWParams, &res, pParams->iColourOffset, 0x40);
|
|
|
|
HP5400_DBG (DBG_MSG, "InitScan2 returned %d\n", ret);
|
|
|
|
/* Pass the results back to the parent */
|
|
pParams->iBytesPerLine = htonl (res.xsize);
|
|
|
|
/* Hide the extra lines we're scanning */
|
|
pParams->iLines = htons (res.ysize);
|
|
|
|
return ret; /* 0 is good, -1 is bad */
|
|
}
|
|
|
|
/* For want of a better name ... */
|
|
HP5400_SANE_STATIC
|
|
int
|
|
InitScan2 (enum ScanType scantype, struct ScanRequest *req,
|
|
THWParams * pHWParams, struct ScanResponse *result,
|
|
int iColourOffset, int code)
|
|
{
|
|
struct ScanResponse res;
|
|
int iHandle = pHWParams->iXferHandle;
|
|
|
|
memset(&res, 0, sizeof(res));
|
|
|
|
/* Protect scanner from damage. This stops stpuid errors. It basically
|
|
* limits you to the scanner glass. Stuff like calibrations which need
|
|
* more access do it safely by fiddling other paramters. Note you can
|
|
* still break things by fiddling the ScanOffset, but that is not yet
|
|
* under user control */
|
|
|
|
if (scantype != SCAN_TYPE_CALIBRATION)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "Off(%d,%d) : Len(%d,%d)\n", htons (req->offx),
|
|
htons (req->offy), htons (req->lenx), htons (req->leny));
|
|
/* Yes, all the htons() is silly but we want this check as late as possible */
|
|
if (htons (req->offx) > 0x09F8)
|
|
req->offx = htons (0x09F8);
|
|
if (htons (req->offy) > 0x0DB6)
|
|
req->offy = htons (0x0DB6);
|
|
/* These tests are meaningless as htons() returns unsigned
|
|
if( htons( req->offx ) < 0 ) req->offx = 0;
|
|
if( htons( req->offy ) < 0 ) req->offy = 0;
|
|
*/
|
|
if (htons (req->offx) + htons (req->lenx) > 0x09F8)
|
|
req->lenx = htons (0x09F8 - htons (req->offx));
|
|
if (htons (req->offy) + htons (req->leny) > 0x0DB6)
|
|
req->leny = htons (0x0DB6 - htons (req->offy));
|
|
if (htons (req->lenx) <= 1)
|
|
return -1;
|
|
if (htons (req->leny) <= 1)
|
|
return -1;
|
|
}
|
|
|
|
WarmupLamp (iHandle);
|
|
|
|
{ /* Try to set it to make scan succeed, URB 53 *//* 0x1B01 => 0x40 */
|
|
/* I think this tries to cancel any existing scan */
|
|
char flag = 0x40;
|
|
if (hp5400_command_write (iHandle, CMD_STOPSCAN, sizeof (flag), &flag) <
|
|
0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to cancel scan flag\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
{ /* Try to set it to make scan succeed, URB 55 */
|
|
char data[4] = { 0x02, 0x03, 0x03, 0x3C };
|
|
if (hp5400_command_write (iHandle, CMD_UNKNOWN3, sizeof (data), data) < 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to set unknown1\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
{ /* Try to set it to make scan succeed, URB 59 */
|
|
char flag = 0x04;
|
|
if (hp5400_command_write (iHandle, CMD_UNKNOWN2, sizeof (flag), &flag) <
|
|
0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to set unknown2\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
{ /* URB 67 *//* Reference DPI = 300 currently */
|
|
short dpi = htons (HW_LPI);
|
|
if (hp5400_command_write (iHandle, CMD_SETDPI, sizeof (dpi), &dpi) < 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to set dpi\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (scantype != SCAN_TYPE_CALIBRATION)
|
|
{ /* Setup scan offsets - Should only apply to non-calibration scans */
|
|
short offsets[2];
|
|
|
|
offsets [0] = htons (0x0054);
|
|
offsets [1] = htons (0x0282);
|
|
|
|
if (hp5400_command_write
|
|
(iHandle, CMD_SETOFFSET, sizeof (offsets), offsets) < 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to set offsets\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
HP5400_DBG (DBG_MSG, "Scan request: \n ");
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < sizeof (*req); i++)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "%02X ", ((unsigned char *) req)[i]);
|
|
}
|
|
HP5400_DBG (DBG_MSG, "\n");
|
|
}
|
|
|
|
if (hp5400_command_write
|
|
(iHandle,
|
|
(scantype !=
|
|
SCAN_TYPE_CALIBRATION) ? CMD_SCANREQUEST2 : CMD_SCANREQUEST,
|
|
sizeof (*req), req) < 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to send scan request\n");
|
|
return -1;
|
|
}
|
|
|
|
{ /* Try to set it to make scan succeed, URB 71 */
|
|
char flag = code; /* Start scan with light on or off as requested */
|
|
if (hp5400_command_write (iHandle, CMD_STARTSCAN, sizeof (flag), &flag) <
|
|
0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to set gamma flag\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (hp5400_command_read (iHandle, CMD_SCANRESPONSE, sizeof (res), &res) < 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to read scan response\n");
|
|
return -1;
|
|
}
|
|
|
|
HP5400_DBG (DBG_MSG, "Scan response: \n ");
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < sizeof (res); i++)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "%02X ", ((unsigned char *) &res)[i]);
|
|
}
|
|
HP5400_DBG (DBG_MSG, "\n");
|
|
}
|
|
|
|
HP5400_DBG (DBG_MSG, "Bytes to transfer: %d\nBitmap resolution: %d x %d\n",
|
|
htonl (res.transfersize), htonl (res.xsize), htons (res.ysize));
|
|
|
|
HP5400_DBG (DBG_MSG, "Proceeding to scan\n");
|
|
|
|
if (htonl (res.transfersize) == 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "Hmm, size is zero. Obviously a problem. Aborting...\n");
|
|
return -1;
|
|
}
|
|
|
|
{
|
|
char x1 = 0x14, x2 = 0x24;
|
|
|
|
float pixels = ((float) htons (req->lenx) * (float) htons (req->leny)) *
|
|
((float) htons (req->dpix) * (float) htons (req->dpiy)) /
|
|
((float) HW_LPI * (float) HW_LPI);
|
|
int bpp = (int) ((float) htonl (res.transfersize) / pixels + 0.5);
|
|
int planes = (bpp == 1) ? 1 : 3;
|
|
bpp /= planes;
|
|
|
|
HP5400_DBG (DBG_MSG, "bpp = %d / ( (%d * %d) * (%d * %d) / (%d * %d) ) = %d\n",
|
|
htonl (res.transfersize),
|
|
htons (req->lenx), htons (req->leny),
|
|
htons (req->dpix), htons (req->dpiy), HW_LPI, HW_LPI, bpp);
|
|
|
|
hp5400_command_write_noverify (iHandle, CMD_INITBULK1, &x1, 1);
|
|
hp5400_command_write_noverify (iHandle, CMD_INITBULK2, &x2, 1);
|
|
|
|
if (bpp > 2) /* Bug!! */
|
|
bpp = 2;
|
|
|
|
CircBufferInit (pHWParams->iXferHandle, &pHWParams->pipe,
|
|
htonl (res.xsize), bpp, iColourOffset, 0xF000,
|
|
htonl (res.transfersize) + 3 * htons (res.ysize));
|
|
}
|
|
|
|
if (result) /* copy ScanResult to parent if they asked for it */
|
|
memcpy (result, &res, sizeof (*result));
|
|
|
|
return 0;
|
|
}
|
|
|
|
HP5400_SANE_STATIC
|
|
void
|
|
FinishScan (THWParams * pHWParams)
|
|
{
|
|
int iHandle = pHWParams->iXferHandle;
|
|
|
|
CircBufferExit (&pHWParams->pipe);
|
|
|
|
{ /* Finish scan request */
|
|
char flag = 0x40;
|
|
if (hp5400_command_write (iHandle, CMD_STOPSCAN, sizeof (flag), &flag) <
|
|
0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to set gamma flag\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
HP5400Open (THWParams * params, const char *filename)
|
|
{
|
|
int iHandle = hp5400_open (filename);
|
|
char szVersion[32];
|
|
int i;
|
|
#ifndef NO_STRING_VERSION_MATCH
|
|
int versionMatched;
|
|
#endif
|
|
|
|
if (iHandle < 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "hp5400_open failed\n");
|
|
return -1;
|
|
}
|
|
|
|
params->iXferHandle = 0;
|
|
|
|
/* read version info */
|
|
if (hp5400_command_read
|
|
(iHandle, CMD_GETVERSION, sizeof (szVersion), szVersion) < 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to read version string\n");
|
|
goto hp5400_close_exit;
|
|
}
|
|
|
|
HP5400_DBG (DBG_MSG, "version String :\n");
|
|
for (i=0; i < 32; i++) {
|
|
HP5400_DBG (DBG_MSG, "%c\n", szVersion[i]);
|
|
}
|
|
HP5400_DBG (DBG_MSG, "\n");
|
|
|
|
#ifndef NO_STRING_VERSION_MATCH
|
|
i = 0;
|
|
versionMatched = 0;
|
|
while ( !versionMatched && (i < numVersions) ) {
|
|
if (!strncmp (szVersion + 1, MatchVersions[i] .strVersion, strlen(MatchVersions[i] .strVersion) - 4)) {
|
|
versionMatched = 1;
|
|
}
|
|
i++;
|
|
}
|
|
if ( !versionMatched ) {
|
|
HP5400_DBG (DBG_MSG,
|
|
"Sorry, unknown scanner version. Attempted match on :\n");
|
|
i = 0;
|
|
while ( i < numVersions ) {
|
|
HP5400_DBG (DBG_MSG, "* '%s'\n", MatchVersions[i] .strVersion);
|
|
i++;
|
|
}
|
|
HP5400_DBG (DBG_MSG, "Version is '%s'\n", szVersion);
|
|
goto hp5400_close_exit;
|
|
}
|
|
#else
|
|
HP5400_DBG (DBG_MSG, "Warning, Version match is disabled. Version is '%s'\n",
|
|
szVersion);
|
|
#endif /* NO_STRING_VERSION_MATCH */
|
|
|
|
params->iXferHandle = iHandle;
|
|
|
|
/* Start the lamp warming up */
|
|
/* No point checking the return value, we don't care anyway */
|
|
WriteByte (iHandle, 0x0000, 0x01);
|
|
|
|
/* Success */
|
|
return 0;
|
|
|
|
hp5400_close_exit:
|
|
hp5400_close (iHandle);
|
|
return -1;
|
|
}
|
|
|
|
HP5400_SANE_STATIC
|
|
void
|
|
HP5400Close (THWParams * params)
|
|
{
|
|
hp5400_close (params->iXferHandle);
|
|
}
|
|
|
|
HP5400_SANE_STATIC
|
|
int
|
|
HP5400Detect (const char *filename,
|
|
int (*_ReportDevice) (TScannerModel * pModel,
|
|
const char *pszDeviceName))
|
|
{
|
|
int iHandle = hp5400_open (filename);
|
|
|
|
char szVersion[32];
|
|
int ret = 0;
|
|
#ifndef NO_STRING_VERSION_MATCH
|
|
int versionMatched = 0;
|
|
int i = 0;
|
|
#endif
|
|
|
|
if (iHandle < 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "hp5400_open failed\n");
|
|
return -1;
|
|
}
|
|
|
|
/* read version info */
|
|
if (hp5400_command_read
|
|
(iHandle, CMD_GETVERSION, sizeof (szVersion), szVersion) < 0)
|
|
{
|
|
HP5400_DBG (DBG_MSG, "failed to read version string\n");
|
|
ret = -1;
|
|
goto hp5400_close_exit;
|
|
}
|
|
|
|
#ifndef NO_STRING_VERSION_MATCH
|
|
i = 0;
|
|
versionMatched = 0;
|
|
while ( !versionMatched && (i < numVersions) ) {
|
|
if (!memcmp (szVersion + 1, MatchVersions[i] .strVersion, strlen (MatchVersions[i] .strVersion) - 4)) {
|
|
versionMatched = 1;
|
|
}
|
|
i++;
|
|
}
|
|
if ( !versionMatched ) {
|
|
HP5400_DBG (DBG_MSG,
|
|
"Sorry, unknown scanner version. Attempted match on :\n");
|
|
i = 0;
|
|
while ( i < numVersions ) {
|
|
HP5400_DBG (DBG_MSG, "* '%s'\n", MatchVersions[i] .strVersion);
|
|
i++;
|
|
}
|
|
HP5400_DBG (DBG_MSG, "Version is '%s'\n", szVersion);
|
|
goto hp5400_close_exit;
|
|
}
|
|
#else
|
|
HP5400_DBG (DBG_MSG, "Warning, Version match is disabled. Version is '%s'\n",
|
|
szVersion);
|
|
#endif /* NO_STRING_VERSION_MATCH */
|
|
|
|
if (_ReportDevice)
|
|
_ReportDevice (&Model_HP54xx, filename);
|
|
|
|
hp5400_close_exit:
|
|
hp5400_close (iHandle);
|
|
return ret;
|
|
}
|
|
|
|
#ifdef STANDALONE
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
THWParams scanner;
|
|
|
|
assert (sizeof (struct ScanRequest) == 32);
|
|
assert (sizeof (struct ScanResponse) == 16);
|
|
|
|
hp5400_dbg_start();
|
|
|
|
HP5400_DBG (DBG_MSG,
|
|
"HP5400/5470C sample scan utility, by Martijn van Oosterhout <kleptog@svana.org>\n");
|
|
HP5400_DBG (DBG_MSG,
|
|
"Based on the testutils by Bertrik Sikken (bertrik@zonnet.nl)\n");
|
|
|
|
if ((argc == 6) && (!strcmp (argv[1], "-decode")))
|
|
{
|
|
int width = atoi (argv[3]);
|
|
int height = atoi (argv[4]);
|
|
FILE *temp = fopen (argv[2], "r+b");
|
|
if (temp)
|
|
{
|
|
int planes = 3;
|
|
int bpp = 1;
|
|
fseek (temp, 0, SEEK_SET);
|
|
DecodeImage (temp, planes, bpp, planes * bpp * width, height,
|
|
argv[5]);
|
|
fclose (temp);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
if (HP5400Open (&scanner, NULL) < 0)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
PreviewScan (scanner.iXferHandle);
|
|
|
|
HP5400Close (&scanner);
|
|
fprintf (stderr, "Note: output is in output.ppm\n");
|
|
return 0;
|
|
}
|
|
|
|
#endif
|