2000-08-12 15:11:46 +00:00
|
|
|
/* sane - Scanner Access Now Easy.
|
|
|
|
|
|
|
|
Copyright (C) 1997, 1998 Franck Schnefra, Michel Roelofs,
|
|
|
|
Emmanuel Blot, Mikko Tyolajarvi, David Mosberger-Tang, Wolfgang Goeller,
|
2001-05-26 12:47:34 +00:00
|
|
|
Petter Reinholdtsen, Gary Plewa, Sebastien Sable and Kevin Charter
|
2000-08-12 15:11:46 +00:00
|
|
|
|
|
|
|
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 is a component of the implementation of a backend for many
|
|
|
|
of the the AGFA SnapScan and Acer Vuego/Prisa flatbed scanners. */
|
|
|
|
|
|
|
|
|
1999-09-16 01:52:00 +00:00
|
|
|
/* $Id$
|
|
|
|
SnapScan backend data sources (implementation) */
|
|
|
|
|
2000-03-05 13:57:25 +00:00
|
|
|
#ifndef __FUNCTION__
|
|
|
|
#define __FUNCTION__ "(undef)"
|
|
|
|
#endif
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status Source_init (Source *pself,
|
|
|
|
SnapScan_Scanner *pss,
|
|
|
|
SourceRemaining remaining,
|
|
|
|
SourceBytesPerLine bytesPerLine,
|
|
|
|
SourcePixelsPerLine pixelsPerLine,
|
|
|
|
SourceGet get,
|
|
|
|
SourceDone done)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
pself->pss = pss;
|
|
|
|
pself->remaining = remaining;
|
|
|
|
pself->bytesPerLine = bytesPerLine;
|
|
|
|
pself->pixelsPerLine = pixelsPerLine;
|
|
|
|
pself->get = get;
|
|
|
|
pself->done = done;
|
|
|
|
return SANE_STATUS_GOOD;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* these are defaults, normally used only by base sources */
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Int Source_bytesPerLine (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
return pself->pss->bytes_per_line;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Int Source_pixelsPerLine (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
return pself->pss->pixels_per_line;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************/
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
/* the base sources */
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
SCSI_SRC,
|
|
|
|
FD_SRC,
|
|
|
|
BUF_SRC
|
|
|
|
} BaseSourceType;
|
1999-09-16 01:52:00 +00:00
|
|
|
|
|
|
|
#define SCSISOURCE_BAD_TIME -1
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
SOURCE_GUTS;
|
|
|
|
SANE_Int scsi_buf_pos; /* current position in scsi buffer */
|
|
|
|
SANE_Int scsi_buf_max; /* data limit */
|
|
|
|
SANE_Int absolute_max; /* largest possible data read */
|
|
|
|
struct timeval time; /* time of last scsi read (usec) */
|
1999-09-16 01:52:00 +00:00
|
|
|
} SCSISource;
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Int SCSISource_remaining (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SCSISource *ps = (SCSISource *) pself;
|
|
|
|
return ps->pss->bytes_remaining + (ps->scsi_buf_max - ps->scsi_buf_pos);
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status SCSISource_get (Source *pself,
|
|
|
|
SANE_Byte *pbuf,
|
|
|
|
SANE_Int *plen)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SCSISource *ps = (SCSISource *) pself;
|
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
SANE_Int remaining = *plen;
|
2001-05-26 12:47:34 +00:00
|
|
|
static SANE_Int warned_expected_bytes = 0;
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
while (remaining > 0
|
|
|
|
&&
|
|
|
|
pself->remaining(pself) > 0
|
|
|
|
&&
|
|
|
|
status == SANE_STATUS_GOOD)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Int ndata = ps->scsi_buf_max - ps->scsi_buf_pos;
|
|
|
|
if (ndata == 0)
|
|
|
|
{
|
|
|
|
/* read more data */
|
|
|
|
struct timeval oldtime = ps->time;
|
|
|
|
if (ps->time.tv_sec != SCSISOURCE_BAD_TIME
|
|
|
|
&&
|
|
|
|
gettimeofday(&(ps->time), NULL) == 0)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
/* estimate number of lines to read from the elapsed time
|
|
|
|
since the last read and the scanner's reported speed */
|
|
|
|
double msecs = (ps->time.tv_sec - oldtime.tv_sec)*1000.0
|
|
|
|
+ (ps->time.tv_usec - oldtime.tv_usec)/1000.0;
|
|
|
|
ps->pss->expected_read_bytes =
|
|
|
|
((int) (msecs/ps->pss->ms_per_line))*ps->pss->bytes_per_line;
|
2001-05-26 12:47:34 +00:00
|
|
|
|
|
|
|
if(ps->pss->pdev->model == ACER300F
|
|
|
|
||
|
|
|
|
ps->pss->pdev->model == SNAPSCAN310
|
|
|
|
||
|
|
|
|
ps->pss->pdev->model == PRISA620S
|
|
|
|
||
|
|
|
|
ps->pss->pdev->model == SNAPSCAN1212U
|
|
|
|
||
|
|
|
|
ps->pss->pdev->model == SNAPSCAN1236S
|
|
|
|
||
|
|
|
|
ps->pss->pdev->model == SNAPSCANE50
|
|
|
|
||
|
|
|
|
ps->pss->pdev->model == VUEGO310S
|
|
|
|
||
|
|
|
|
ps->pss->pdev->model == VUEGO610S)
|
|
|
|
{
|
|
|
|
ps->pss->expected_read_bytes = (size_t) ps->absolute_max;
|
|
|
|
}
|
|
|
|
if (ps->pss->expected_read_bytes == 0)
|
|
|
|
{
|
|
|
|
if (!warned_expected_bytes)
|
|
|
|
{
|
|
|
|
warned_expected_bytes++;
|
|
|
|
|
|
|
|
DBG (DL_MAJOR_ERROR,
|
|
|
|
"%s: Hung up because expected bytes is 0. Please report!",
|
|
|
|
__FUNCTION__);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* use the "lines_per_read" values */
|
|
|
|
SANE_Int lines;
|
|
|
|
|
|
|
|
if (is_colour_mode(actual_mode(ps->pss)) == SANE_TRUE)
|
|
|
|
lines = ps->pss->rgb_lpr;
|
|
|
|
else
|
|
|
|
lines = ps->pss->gs_lpr;
|
|
|
|
ps->pss->expected_read_bytes = lines * ps->pss->bytes_per_line;
|
|
|
|
}
|
|
|
|
ps->pss->expected_read_bytes = MIN(ps->pss->expected_read_bytes,
|
|
|
|
ps->pss->bytes_remaining);
|
|
|
|
ps->pss->expected_read_bytes = MIN(ps->pss->expected_read_bytes,
|
|
|
|
(size_t) ps->absolute_max);
|
|
|
|
ps->scsi_buf_pos = 0;
|
|
|
|
ps->scsi_buf_max = 0;
|
|
|
|
status = scsi_read (ps->pss, READ_IMAGE);
|
|
|
|
if (status != SANE_STATUS_GOOD)
|
|
|
|
break;
|
|
|
|
ps->scsi_buf_max = ps->pss->read_bytes;
|
|
|
|
ndata = ps->pss->read_bytes;
|
|
|
|
ps->pss->bytes_remaining -= ps->pss->read_bytes;
|
|
|
|
}
|
|
|
|
ndata = MIN(ndata, remaining);
|
|
|
|
memcpy (pbuf, ps->pss->buf + ps->scsi_buf_pos, (size_t)ndata);
|
|
|
|
pbuf += ndata;
|
|
|
|
ps->scsi_buf_pos += ndata;
|
|
|
|
remaining -= ndata;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
*plen -= remaining;
|
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status SCSISource_done (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
UNREFERENCED_PARAMETER(pself);
|
|
|
|
return SANE_STATUS_GOOD;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status SCSISource_init (SCSISource *pself, SnapScan_Scanner *pss)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = Source_init ((Source *) pself, pss,
|
|
|
|
SCSISource_remaining,
|
|
|
|
Source_bytesPerLine,
|
|
|
|
Source_pixelsPerLine,
|
|
|
|
SCSISource_get,
|
|
|
|
SCSISource_done);
|
|
|
|
if (status == SANE_STATUS_GOOD)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
pself->scsi_buf_max = 0;
|
|
|
|
pself->scsi_buf_pos = 0;
|
|
|
|
pself->absolute_max =
|
|
|
|
(SCANNER_BUF_SZ/pss->bytes_per_line)*pss->bytes_per_line;
|
|
|
|
if (gettimeofday(&(pself->time), NULL) != 0)
|
|
|
|
{
|
|
|
|
DBG (DL_MAJOR_ERROR,
|
|
|
|
"%s: error in gettimeofday(): %s\n",
|
|
|
|
__FUNCTION__,
|
|
|
|
strerror(errno));
|
|
|
|
pself->time.tv_sec = SCSISOURCE_BAD_TIME;
|
|
|
|
pself->time.tv_usec = SCSISOURCE_BAD_TIME;
|
|
|
|
}
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* File sources */
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
SOURCE_GUTS;
|
|
|
|
int fd;
|
1999-09-16 01:52:00 +00:00
|
|
|
} FDSource;
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Int FDSource_remaining (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
return pself->pss->bytes_remaining;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status FDSource_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
FDSource *ps = (FDSource *) pself;
|
|
|
|
SANE_Int remaining = *plen;
|
1999-09-16 01:52:00 +00:00
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
while (remaining > 0
|
|
|
|
&&
|
|
|
|
pself->remaining(pself) > 0
|
|
|
|
&&
|
|
|
|
status == SANE_STATUS_GOOD)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Int bytes_read = read (ps->fd, pbuf, remaining);
|
|
|
|
if (bytes_read == -1)
|
|
|
|
{
|
|
|
|
if (errno == EAGAIN)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
/* No data currently available */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* It's an IO error */
|
|
|
|
DBG (DL_MAJOR_ERROR,
|
|
|
|
"%s: read failed: %s\n",
|
|
|
|
__FUNCTION__,
|
|
|
|
strerror(errno));
|
|
|
|
status = SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
|
|
|
else if (bytes_read == 0)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
break;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
ps->pss->bytes_remaining -= bytes_read;
|
|
|
|
remaining -= bytes_read;
|
|
|
|
pbuf += bytes_read;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
*plen -= remaining;
|
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status FDSource_done (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
close(((FDSource *) pself)->fd);
|
|
|
|
return SANE_STATUS_GOOD;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status FDSource_init (FDSource *pself,
|
|
|
|
SnapScan_Scanner *pss,
|
|
|
|
int fd)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = Source_init ((Source *) pself,
|
|
|
|
pss,
|
|
|
|
FDSource_remaining,
|
|
|
|
Source_bytesPerLine,
|
|
|
|
Source_pixelsPerLine,
|
|
|
|
FDSource_get,
|
|
|
|
FDSource_done);
|
|
|
|
if (status == SANE_STATUS_GOOD)
|
|
|
|
pself->fd = fd;
|
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* buffer sources simply read from a pre-filled buffer; we have these
|
|
|
|
so that we can include source chain processing overhead in the
|
|
|
|
measure_transfer_rate() function */
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
SOURCE_GUTS;
|
|
|
|
SANE_Byte *buf;
|
|
|
|
SANE_Int buf_size;
|
|
|
|
SANE_Int buf_pos;
|
1999-09-16 01:52:00 +00:00
|
|
|
} BufSource;
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Int BufSource_remaining (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
BufSource *ps = (BufSource *) pself;
|
|
|
|
return ps->buf_size - ps->buf_pos;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status BufSource_get (Source *pself,
|
|
|
|
SANE_Byte *pbuf,
|
|
|
|
SANE_Int *plen)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
BufSource *ps = (BufSource *) pself;
|
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
SANE_Int to_move = MIN(*plen, pself->remaining(pself));
|
2001-05-26 12:47:34 +00:00
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
if (to_move == 0)
|
|
|
|
{
|
|
|
|
status = SANE_STATUS_EOF;
|
|
|
|
}
|
|
|
|
else
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
memcpy (pbuf, ps->buf + ps->buf_pos, to_move);
|
|
|
|
ps->buf_pos += to_move;
|
|
|
|
*plen = to_move;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status BufSource_done (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
UNREFERENCED_PARAMETER(pself);
|
|
|
|
return SANE_STATUS_GOOD;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status BufSource_init (BufSource *pself,
|
|
|
|
SnapScan_Scanner *pss,
|
|
|
|
SANE_Byte *buf,
|
|
|
|
SANE_Int buf_size)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = Source_init ((Source *) pself,
|
|
|
|
pss,
|
|
|
|
BufSource_remaining,
|
|
|
|
Source_bytesPerLine,
|
|
|
|
Source_pixelsPerLine,
|
|
|
|
BufSource_get,
|
|
|
|
BufSource_done);
|
|
|
|
if (status == SANE_STATUS_GOOD)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
pself->buf = buf;
|
|
|
|
pself->buf_size = buf_size;
|
|
|
|
pself->buf_pos = 0;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* base source creation */
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status create_base_source (SnapScan_Scanner *pss,
|
|
|
|
BaseSourceType st,
|
|
|
|
Source **pps)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
*pps = NULL;
|
|
|
|
switch (st)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
|
|
|
case SCSI_SRC:
|
2000-08-12 15:11:46 +00:00
|
|
|
*pps = (Source *) malloc(sizeof(SCSISource));
|
|
|
|
if (*pps == NULL)
|
|
|
|
{
|
|
|
|
DBG (DL_MAJOR_ERROR, "failed to allocate SCSISource");
|
|
|
|
status = SANE_STATUS_NO_MEM;
|
|
|
|
}
|
|
|
|
else
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
status = SCSISource_init ((SCSISource *) *pps, pss);
|
|
|
|
}
|
|
|
|
break;
|
1999-09-16 01:52:00 +00:00
|
|
|
case FD_SRC:
|
2000-08-12 15:11:46 +00:00
|
|
|
*pps = (Source *) malloc(sizeof(FDSource));
|
|
|
|
if (*pps == NULL)
|
|
|
|
{
|
|
|
|
DBG (DL_MAJOR_ERROR, "failed to allocate FDSource");
|
|
|
|
status = SANE_STATUS_NO_MEM;
|
|
|
|
}
|
|
|
|
else
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
status = FDSource_init ((FDSource *) *pps, pss, pss->rpipe[0]);
|
|
|
|
}
|
|
|
|
break;
|
1999-09-16 01:52:00 +00:00
|
|
|
case BUF_SRC:
|
2000-08-12 15:11:46 +00:00
|
|
|
*pps = (Source *) malloc(sizeof(BufSource));
|
|
|
|
if (*pps == NULL)
|
|
|
|
{
|
|
|
|
DBG (DL_MAJOR_ERROR, "failed to allocate BufSource");
|
|
|
|
status = SANE_STATUS_NO_MEM;
|
|
|
|
}
|
|
|
|
else
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
status = BufSource_init ((BufSource *) *pps,
|
|
|
|
pss,
|
|
|
|
pss->buf,
|
|
|
|
pss->read_bytes);
|
|
|
|
}
|
|
|
|
break;
|
1999-09-16 01:52:00 +00:00
|
|
|
default:
|
2000-08-12 15:11:46 +00:00
|
|
|
DBG (DL_MAJOR_ERROR, "illegal base source type %d", st);
|
|
|
|
break;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************/
|
2000-08-12 15:11:46 +00:00
|
|
|
|
|
|
|
/* The transformer sources */
|
1999-09-16 01:52:00 +00:00
|
|
|
|
|
|
|
#define TX_SOURCE_GUTS \
|
2000-08-12 15:11:46 +00:00
|
|
|
SOURCE_GUTS;\
|
|
|
|
Source *psub /* sub-source */
|
1999-09-16 01:52:00 +00:00
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
TX_SOURCE_GUTS;
|
1999-09-16 01:52:00 +00:00
|
|
|
} TxSource;
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Int TxSource_remaining (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
TxSource *ps = (TxSource *) pself;
|
|
|
|
return ps->psub->remaining(ps->psub);
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Int TxSource_bytesPerLine (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
TxSource *ps = (TxSource *) pself;
|
|
|
|
return ps->psub->bytesPerLine(ps->psub);
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Int TxSource_pixelsPerLine (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
TxSource *ps = (TxSource *) pself;
|
|
|
|
return ps->psub->pixelsPerLine(ps->psub);
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status TxSource_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
TxSource *ps = (TxSource *) pself;
|
|
|
|
return ps->psub->get(ps->psub, pbuf, plen);
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status TxSource_done (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
TxSource *ps = (TxSource *) pself;
|
|
|
|
SANE_Status status = ps->psub->done(ps->psub);
|
|
|
|
free(ps->psub);
|
|
|
|
ps->psub = NULL;
|
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status TxSource_init (TxSource *pself,
|
|
|
|
SnapScan_Scanner *pss,
|
|
|
|
SourceRemaining remaining,
|
|
|
|
SourceBytesPerLine bytesPerLine,
|
|
|
|
SourcePixelsPerLine pixelsPerLine,
|
|
|
|
SourceGet get,
|
|
|
|
SourceDone done,
|
|
|
|
Source *psub)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = Source_init((Source *) pself,
|
|
|
|
pss,
|
|
|
|
remaining,
|
|
|
|
bytesPerLine,
|
|
|
|
pixelsPerLine,
|
|
|
|
get,
|
|
|
|
done);
|
|
|
|
if (status == SANE_STATUS_GOOD)
|
|
|
|
pself->psub = psub;
|
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
/* The expander makes three-channel, one-bit, raw scanner data into
|
|
|
|
8-bit data. It is used to support the bilevel colour scanning mode */
|
1999-09-16 01:52:00 +00:00
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
TX_SOURCE_GUTS;
|
|
|
|
SANE_Byte *ch_buf; /* channel buffer */
|
|
|
|
SANE_Int ch_size; /* channel buffer size = #bytes in a channel */
|
|
|
|
SANE_Int ch_ndata; /* actual #bytes in channel buffer */
|
|
|
|
SANE_Int ch_pos; /* position in buffer */
|
|
|
|
SANE_Int bit; /* current bit */
|
|
|
|
SANE_Int last_bit; /* current last bit (counting down) */
|
|
|
|
SANE_Int last_last_bit; /* last bit in the last byte of the channel */
|
1999-09-16 01:52:00 +00:00
|
|
|
} Expander;
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Int Expander_remaining (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
Expander *ps = (Expander *) pself;
|
|
|
|
SANE_Int sub_remaining = TxSource_remaining(pself);
|
|
|
|
SANE_Int sub_bits_per_channel = TxSource_pixelsPerLine(pself);
|
|
|
|
SANE_Int whole_channels = sub_remaining/ps->ch_size;
|
|
|
|
SANE_Int result = whole_channels*sub_bits_per_channel;
|
1999-09-16 01:52:00 +00:00
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
if (ps->ch_pos < ps->ch_size)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Int bits_covered = MAX((ps->ch_pos - 1)*8, 0) + 7 - ps->bit;
|
|
|
|
result += sub_bits_per_channel - bits_covered;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
return result;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Int Expander_bytesPerLine (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
return TxSource_pixelsPerLine(pself)*3;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status Expander_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
Expander *ps = (Expander *) pself;
|
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
SANE_Int remaining = *plen;
|
1999-09-16 01:52:00 +00:00
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
while (remaining > 0
|
|
|
|
&&
|
|
|
|
pself->remaining(pself) > 0)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
if (ps->ch_pos == ps->ch_ndata)
|
|
|
|
{
|
|
|
|
/* we need more data; try to get the remainder of the current
|
|
|
|
channel, or else the next channel */
|
|
|
|
SANE_Int ndata = ps->ch_size - ps->ch_ndata;
|
|
|
|
if (ndata == 0)
|
|
|
|
{
|
|
|
|
ps->ch_ndata = 0;
|
|
|
|
ps->ch_pos = 0;
|
|
|
|
ndata = ps->ch_size;
|
|
|
|
}
|
|
|
|
status = TxSource_get(pself, ps->ch_buf + ps->ch_pos, &ndata);
|
|
|
|
if (status != SANE_STATUS_GOOD)
|
|
|
|
break;
|
|
|
|
if (ndata == 0)
|
|
|
|
break;
|
|
|
|
ps->ch_ndata += ndata;
|
|
|
|
if (ps->ch_pos == (ps->ch_size - 1))
|
|
|
|
ps->last_bit = ps->last_last_bit;
|
|
|
|
else
|
|
|
|
ps->last_bit = 0;
|
|
|
|
ps->bit = 7;
|
|
|
|
}
|
|
|
|
*pbuf = ((ps->ch_buf[ps->ch_pos] >> ps->bit) & 0x01) ? 0xFF : 0x00;
|
|
|
|
pbuf++;
|
|
|
|
remaining--;
|
|
|
|
|
|
|
|
if (ps->bit == ps->last_bit)
|
|
|
|
{
|
|
|
|
ps->bit = 7;
|
|
|
|
ps->ch_pos++;
|
|
|
|
if (ps->ch_pos == (ps->ch_size - 1))
|
|
|
|
ps->last_bit = ps->last_last_bit;
|
|
|
|
else
|
|
|
|
ps->last_bit = 0;
|
|
|
|
}
|
|
|
|
else
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
ps->bit--;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
*plen -= remaining;
|
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status Expander_done (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
Expander *ps = (Expander *) pself;
|
|
|
|
SANE_Status status = TxSource_done(pself);
|
|
|
|
free(ps->ch_buf);
|
|
|
|
ps->ch_buf = NULL;
|
|
|
|
ps->ch_size = 0;
|
|
|
|
ps->ch_pos = 0;
|
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status Expander_init (Expander *pself,
|
|
|
|
SnapScan_Scanner *pss,
|
|
|
|
Source *psub)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = TxSource_init((TxSource *) pself,
|
|
|
|
pss,
|
|
|
|
Expander_remaining,
|
|
|
|
Expander_bytesPerLine,
|
|
|
|
TxSource_pixelsPerLine,
|
|
|
|
Expander_get,
|
|
|
|
Expander_done,
|
|
|
|
psub);
|
|
|
|
if (status == SANE_STATUS_GOOD)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
pself->ch_size = TxSource_bytesPerLine((Source *) pself)/3;
|
|
|
|
pself->ch_buf = (SANE_Byte *) malloc(pself->ch_size);
|
|
|
|
if (pself->ch_buf == NULL)
|
|
|
|
{
|
|
|
|
DBG (DL_MAJOR_ERROR,
|
|
|
|
"%s: couldn't allocate channel buffer.\n",
|
|
|
|
__FUNCTION__);
|
|
|
|
status = SANE_STATUS_NO_MEM;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pself->ch_ndata = 0;
|
|
|
|
pself->ch_pos = 0;
|
|
|
|
pself->last_last_bit = pself->pixelsPerLine((Source *) pself)%8;
|
|
|
|
if (pself->last_last_bit == 0)
|
|
|
|
pself->last_last_bit = 7;
|
|
|
|
pself->last_last_bit = 7 - pself->last_last_bit;
|
|
|
|
pself->bit = 7;
|
|
|
|
if (pself->ch_size > 1)
|
|
|
|
pself->last_bit = 0;
|
|
|
|
else
|
|
|
|
pself->last_bit = pself->last_last_bit;
|
|
|
|
}
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status create_Expander (SnapScan_Scanner *pss,
|
|
|
|
Source *psub,
|
|
|
|
Source **pps)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
*pps = (Source *) malloc(sizeof(Expander));
|
|
|
|
if (*pps == NULL)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
DBG (DL_MAJOR_ERROR,
|
|
|
|
"%s: failed to allocate Expander.\n",
|
|
|
|
__FUNCTION__);
|
|
|
|
status = SANE_STATUS_NO_MEM;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
status = Expander_init ((Expander *) *pps, pss, psub);
|
|
|
|
}
|
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* the RGB router assumes 8-bit RGB data arranged in contiguous
|
|
|
|
channels, possibly with R-G and R-B offsets, and rearranges the
|
2000-08-12 15:11:46 +00:00
|
|
|
data into SANE RGB frame format */
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
TX_SOURCE_GUTS;
|
|
|
|
SANE_Byte *cbuf; /* circular line buffer */
|
|
|
|
SANE_Byte *xbuf; /* single line buffer */
|
|
|
|
SANE_Int pos; /* current position in xbuf */
|
|
|
|
SANE_Int cb_size; /* size of the circular buffer */
|
|
|
|
SANE_Int cb_line_size; /* size of a line in the circular buffer */
|
|
|
|
SANE_Int cb_start; /* start of valid data in the circular buffer */
|
|
|
|
SANE_Int ch_offset[3]; /* offset in cbuf */
|
1999-09-16 01:52:00 +00:00
|
|
|
} RGBRouter;
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Int RGBRouter_remaining (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
RGBRouter *ps = (RGBRouter *) pself;
|
2001-05-26 12:47:34 +00:00
|
|
|
SANE_Int remaining;
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
if (ps->cb_start < 0)
|
2001-05-26 12:47:34 +00:00
|
|
|
remaining = (TxSource_remaining(pself) - ps->cb_size + ps->cb_line_size);
|
|
|
|
else
|
|
|
|
remaining = (TxSource_remaining(pself) + ps->cb_line_size - ps->pos);
|
|
|
|
|
|
|
|
if (remaining < 0)
|
|
|
|
{
|
|
|
|
/* We are in big trouble. Someone is using the RBGRouter routines
|
|
|
|
* to find out how much is remaining. There is a case were not
|
|
|
|
* enough data has been read yet to fill the circular buffer.
|
|
|
|
* Until it is filled then no one should be accessing it or
|
|
|
|
* checking how much is remaining (in current implemntation).
|
|
|
|
* FIXME: For now, there is some code (measure_transfer_rate) that
|
|
|
|
* will do this at times and setting remaining = 1 allows some
|
|
|
|
* scans to squeak by.
|
|
|
|
*/
|
|
|
|
remaining = 1;
|
|
|
|
DBG (DL_MAJOR_ERROR,
|
|
|
|
"%s: Computed a negative size for circular buffer! Forcing to size of 1 to keep going\n",
|
|
|
|
__FUNCTION__);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return (remaining);
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status RGBRouter_get (Source *pself,
|
|
|
|
SANE_Byte *pbuf,
|
|
|
|
SANE_Int *plen)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
RGBRouter *ps = (RGBRouter *) pself;
|
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
SANE_Int remaining = *plen;
|
|
|
|
SANE_Byte *s;
|
|
|
|
SANE_Int i;
|
|
|
|
SANE_Int r;
|
|
|
|
SANE_Int g;
|
|
|
|
SANE_Int b;
|
1999-09-16 01:52:00 +00:00
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
while (remaining > 0 && pself->remaining(pself) > 0)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
if (ps->pos >= ps->cb_line_size)
|
|
|
|
{
|
|
|
|
/* Try to get more data */
|
2001-05-26 12:47:34 +00:00
|
|
|
SANE_Int ndata = (ps->cb_start < 0) ? ps->cb_size : (ps->cb_line_size - ps->cb_start%ps->cb_line_size);
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Int start = (ps->cb_start < 0) ? 0 : ps->cb_start;
|
|
|
|
SANE_Int ndata2;
|
|
|
|
SANE_Int ndata3;
|
|
|
|
|
|
|
|
ndata2 = ndata;
|
|
|
|
ndata3 = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
status = TxSource_get (pself, ps->cbuf + start + ndata3, &ndata2);
|
|
|
|
if (status != SANE_STATUS_GOOD || ndata2 == 0)
|
|
|
|
{
|
2001-05-26 12:47:34 +00:00
|
|
|
DBG (DL_MINOR_ERROR,
|
|
|
|
"TxSource_get failed status:%d, ndata:%d, ndata2:%d ndata3:%d\n", status, ndata, ndata2, ndata3);
|
|
|
|
ps->cb_start = (start + ndata3)%ps->cb_size;
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
*plen -= remaining;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
ndata3 += ndata2;
|
|
|
|
ndata2 = ndata - ndata3;
|
|
|
|
}
|
|
|
|
while (ndata3 < ndata);
|
|
|
|
ps->cb_start = (start + ndata3)%ps->cb_size;
|
|
|
|
s = ps->xbuf;
|
|
|
|
r = (ps->cb_start + ps->ch_offset[0])%ps->cb_size;
|
|
|
|
g = (ps->cb_start + ps->ch_offset[1])%ps->cb_size;
|
|
|
|
b = (ps->cb_start + ps->ch_offset[2])%ps->cb_size;
|
|
|
|
for (i = 0; i < ps->cb_line_size/3; i++)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
*s++ = ps->cbuf[r++];
|
|
|
|
*s++ = ps->cbuf[g++];
|
|
|
|
*s++ = ps->cbuf[b++];
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
ps->pos = 0;
|
|
|
|
}
|
|
|
|
/* Repack the whole scan line now */
|
|
|
|
while (remaining > 0 && ps->pos < ps->cb_line_size)
|
|
|
|
{
|
|
|
|
*pbuf++ = ps->xbuf[ps->pos++];
|
|
|
|
remaining--;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
*plen -= remaining;
|
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status RGBRouter_done (Source *pself)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
RGBRouter *ps = (RGBRouter *) pself;
|
|
|
|
SANE_Status status = TxSource_done(pself);
|
1999-09-16 01:52:00 +00:00
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
free(ps->cbuf);
|
|
|
|
free(ps->xbuf);
|
|
|
|
ps->cbuf = NULL;
|
|
|
|
ps->cb_start = -1;
|
|
|
|
ps->pos = 0;
|
|
|
|
return status;
|
|
|
|
}
|
1999-09-16 01:52:00 +00:00
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status RGBRouter_init (RGBRouter *pself,
|
|
|
|
SnapScan_Scanner *pss,
|
|
|
|
Source *psub)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = TxSource_init((TxSource *) pself,
|
|
|
|
pss,
|
|
|
|
RGBRouter_remaining,
|
|
|
|
TxSource_bytesPerLine,
|
|
|
|
TxSource_pixelsPerLine,
|
|
|
|
RGBRouter_get,
|
|
|
|
RGBRouter_done,
|
|
|
|
psub);
|
|
|
|
if (status == SANE_STATUS_GOOD)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Int lines_in_buffer = 1;
|
|
|
|
SANE_Int ch;
|
|
|
|
|
|
|
|
/* Size the buffer to accomodate the necessary number of scan lines
|
|
|
|
to cater for the offset between R, G and B */
|
|
|
|
lines_in_buffer = 0;
|
|
|
|
for (ch = 0; ch < 3; ch++)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
if (pss->chroma_offset[ch] > lines_in_buffer)
|
|
|
|
lines_in_buffer = pss->chroma_offset[ch];
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
lines_in_buffer++;
|
|
|
|
|
|
|
|
pself->cb_line_size = pself->bytesPerLine((Source *) pself);
|
|
|
|
pself->cb_size = pself->cb_line_size*lines_in_buffer;
|
|
|
|
pself->pos = pself->cb_line_size;
|
|
|
|
pself->cbuf = (SANE_Byte *) malloc(pself->cb_size);
|
|
|
|
pself->xbuf = (SANE_Byte *) malloc(pself->cb_line_size);
|
|
|
|
if (pself->cbuf == NULL || pself->xbuf == NULL)
|
|
|
|
{
|
|
|
|
DBG (DL_MAJOR_ERROR,
|
|
|
|
"%s: failed to allocate circular buffer.\n",
|
|
|
|
__FUNCTION__);
|
|
|
|
status = SANE_STATUS_NO_MEM;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SANE_Int ch;
|
|
|
|
|
|
|
|
pself->cb_start = -1;
|
|
|
|
for (ch = 0; ch < 3; ch++)
|
|
|
|
{
|
|
|
|
pself->ch_offset[ch] = pss->chroma_offset[ch]*pself->bytesPerLine((Source *) pself)
|
|
|
|
+ ch*(pself->bytesPerLine((Source *) pself)/3);
|
|
|
|
}
|
|
|
|
}
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status create_RGBRouter (SnapScan_Scanner *pss,
|
|
|
|
Source *psub,
|
|
|
|
Source **pps)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
*pps = (Source *) malloc(sizeof(RGBRouter));
|
|
|
|
if (*pps == NULL)
|
|
|
|
{
|
|
|
|
DBG (DL_MAJOR_ERROR,
|
|
|
|
"%s: failed to allocate RGBRouter.\n",
|
|
|
|
__FUNCTION__);
|
|
|
|
status = SANE_STATUS_NO_MEM;
|
|
|
|
}
|
|
|
|
else
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
status = RGBRouter_init ((RGBRouter *) *pps, pss, psub);
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
/* An Inverter is used to invert the bits in a lineart image */
|
1999-09-16 01:52:00 +00:00
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
TX_SOURCE_GUTS;
|
1999-09-16 01:52:00 +00:00
|
|
|
} Inverter;
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status Inverter_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = TxSource_get (pself, pbuf, plen);
|
|
|
|
if (status == SANE_STATUS_GOOD)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < *plen; i++)
|
|
|
|
pbuf[i] ^= 0xFF;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status Inverter_init (Inverter *pself,
|
|
|
|
SnapScan_Scanner *pss,
|
|
|
|
Source *psub)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
return TxSource_init ((TxSource *) pself,
|
|
|
|
pss,
|
|
|
|
TxSource_remaining,
|
|
|
|
TxSource_bytesPerLine,
|
|
|
|
TxSource_pixelsPerLine,
|
|
|
|
Inverter_get,
|
|
|
|
TxSource_done,
|
|
|
|
psub);
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status create_Inverter (SnapScan_Scanner *pss,
|
|
|
|
Source *psub,
|
|
|
|
Source **pps)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
*pps = (Source *) malloc(sizeof(Inverter));
|
|
|
|
if (*pps == NULL)
|
|
|
|
{
|
|
|
|
DBG (DL_MAJOR_ERROR,
|
|
|
|
"%s: failed to allocate Inverter.\n",
|
|
|
|
__FUNCTION__);
|
|
|
|
status = SANE_STATUS_NO_MEM;
|
|
|
|
}
|
|
|
|
else
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
status = Inverter_init ((Inverter *) *pps, pss, psub);
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
return status;
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
/* Source chain creation */
|
1999-09-16 01:52:00 +00:00
|
|
|
|
2000-08-12 15:11:46 +00:00
|
|
|
static SANE_Status create_source_chain (SnapScan_Scanner *pss,
|
|
|
|
BaseSourceType bst,
|
|
|
|
Source **pps)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SANE_Status status = create_base_source (pss, bst, pps);
|
|
|
|
if (status == SANE_STATUS_GOOD)
|
1999-09-16 01:52:00 +00:00
|
|
|
{
|
2000-08-12 15:11:46 +00:00
|
|
|
SnapScan_Mode mode = actual_mode(pss);
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case MD_COLOUR:
|
|
|
|
status = create_RGBRouter (pss, *pps, pps);
|
|
|
|
break;
|
|
|
|
case MD_BILEVELCOLOUR:
|
|
|
|
status = create_Expander (pss, *pps, pps);
|
|
|
|
if (status == SANE_STATUS_GOOD)
|
|
|
|
status = create_RGBRouter (pss, *pps, pps);
|
|
|
|
break;
|
|
|
|
case MD_GREYSCALE:
|
|
|
|
break;
|
|
|
|
case MD_LINEART:
|
|
|
|
/* The SnapScan creates a negative image by
|
|
|
|
default... so for the user interface to make sense,
|
|
|
|
the internal meaning of "negative" is reversed */
|
|
|
|
if (pss->negative == SANE_FALSE)
|
|
|
|
status = create_Inverter (pss, *pps, pps);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DBG (DL_MAJOR_ERROR,
|
|
|
|
"%s: bad mode value %d (internal error)\n",
|
|
|
|
__FUNCTION__,
|
|
|
|
mode);
|
|
|
|
status = SANE_STATUS_INVAL;
|
|
|
|
break;
|
|
|
|
}
|
1999-09-16 01:52:00 +00:00
|
|
|
}
|
2000-08-12 15:11:46 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* $Log$
|
2001-05-26 12:47:34 +00:00
|
|
|
* Revision 1.4 2001/05/26 12:47:31 hmg
|
|
|
|
* Updated snapscan backend to version 1.2 (from
|
|
|
|
* Sebastien Sable <Sebastien.Sable@snv.jussieu.fr>).
|
|
|
|
* Henning Meier-Geinitz <henning@meier-geinitz.de>
|
|
|
|
*
|
|
|
|
* Revision 1.11 2001/04/13 13:12:18 oliverschwartz
|
|
|
|
* use absolute_max as expected_read_bytes for PRISA620S
|
|
|
|
*
|
|
|
|
* Revision 1.10 2001/04/10 11:04:31 sable
|
|
|
|
* Adding support for snapscan e40 an e50 thanks to Giuseppe Tanzilli
|
|
|
|
*
|
|
|
|
* Revision 1.9 2001/03/17 22:53:21 sable
|
|
|
|
* Applying Mikael Magnusson patch concerning Gamma correction
|
|
|
|
* Support for 1212U_2
|
|
|
|
*
|
|
|
|
* Revision 1.3 2001/03/04 16:53:21 mikael
|
|
|
|
* Reading absolute max from SNAPSCAN 1212U
|
|
|
|
*
|
|
|
|
* Revision 1.2 2001/02/16 18:32:28 mikael
|
|
|
|
* impl calibration, signed position, increased buffer size
|
|
|
|
*
|
|
|
|
* Revision 1.1.1.1 2001/02/10 17:09:29 mikael
|
|
|
|
* Imported from snapscan-11282000.tar.gz
|
|
|
|
*
|
|
|
|
* Revision 1.8 2000/11/28 03:55:07 cbagwell
|
|
|
|
* Reverting a fix to RGBRouter_remaining to original fix. This allows
|
|
|
|
* most scanners to scan at 600 dpi by ignoring insufficent data in
|
|
|
|
* the RGB circular buffer and always returning size = 1 in those cases.
|
|
|
|
* This should probably be fixed at a higher level.
|
|
|
|
*
|
|
|
|
* Revision 1.7 2000/11/20 01:02:42 cbagwell
|
|
|
|
* Updates so that USB will continue reading when it receives an EAGAIN error.
|
|
|
|
* Also, changed RGBRouter_remaining to not be able to return a negative
|
|
|
|
* value.
|
|
|
|
*
|
|
|
|
* Revision 1.6 2000/11/04 01:53:58 cbagwell
|
|
|
|
* Commiting some needed USB updates. Added extra test logic to detect
|
|
|
|
* bad bytes_expected values. Just to help debug faster on scanners
|
|
|
|
* that tickle the bug.
|
|
|
|
*
|
|
|
|
* Revision 1.5 2000/10/30 22:32:20 sable
|
|
|
|
* Support for vuego310s vuego610s and 1236s
|
|
|
|
*
|
|
|
|
* Revision 1.4 2000/10/28 14:16:10 sable
|
|
|
|
* Bug correction for SnapScan310
|
|
|
|
*
|
|
|
|
* Revision 1.3 2000/10/28 14:06:35 sable
|
|
|
|
* Add support for Acer300f
|
|
|
|
*
|
|
|
|
* Revision 1.2 2000/10/13 03:50:27 cbagwell
|
|
|
|
* Updating to source from SANE 1.0.3. Calling this versin 1.1
|
|
|
|
*
|
2000-08-12 15:11:46 +00:00
|
|
|
* Revision 1.3 2000/08/12 15:09:35 pere
|
|
|
|
* Merge devel (v1.0.3) into head branch.
|
|
|
|
*
|
|
|
|
* Revision 1.1.2.2 2000/07/13 04:47:45 pere
|
|
|
|
* New snapscan backend version dated 20000514 from Steve Underwood.
|
|
|
|
*
|
|
|
|
* Revision 1.2.1 2000/05/14 13:30:20 coppice
|
|
|
|
* Added history log to pre-existing code.Some reformatting.
|
|
|
|
* R, G and B images now merge correctly. There are still some outstanding
|
|
|
|
* issues in this area, but its a lot more usable than before.
|
|
|
|
* */
|