sane-project-backends/backend/snapscan-scsi.c

1948 wiersze
61 KiB
C

/* sane - Scanner Access Now Easy.
Copyright (C) 1997, 1998, 2001, 2002, 2013 Franck Schnefra, Michel Roelofs,
Emmanuel Blot, Mikko Tyolajarvi, David Mosberger-Tang, Wolfgang Goeller,
Petter Reinholdtsen, Gary Plewa, Sebastien Sable, Mikael Magnusson,
Max Ushakov, Andrew Goodbody, Oliver Schwartz and Kevin Charter
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, see <https://www.gnu.org/licenses/>.
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 AGFA SnapScan and Acer Vuego/Prisa flatbed scanners.
*/
/*
SnapScan backend scsi command functions
*/
/* scanner scsi commands */
static SANE_Status download_firmware(SnapScan_Scanner * pss);
static SANE_Status wait_scanner_ready (SnapScan_Scanner * pss);
#include "snapscan-usb.h"
/* find model by SCSI ID string or USB vendor/product ID */
static SnapScan_Model snapscani_get_model_id(char* model_str, int fd, SnapScan_Bus bus_type)
{
static char me[] = "snapscani_get_model_id";
SnapScan_Model model_id = UNKNOWN;
SANE_Word vendor_id, product_id;
int i;
DBG(DL_CALL_TRACE, "%s(%s, %d, %d)\n",me, model_str, fd, bus_type);
for (i = 0; i < known_scanners; i++)
{
if (0 == strcasecmp (model_str, scanners[i].scsi_name))
{
model_id = scanners[i].id;
break;
}
}
/* Also test USB vendor and product ID numbers, since some USB models use
identical model names.
*/
if ((bus_type == USB) &&
(sanei_usb_get_vendor_product(fd, &vendor_id, &product_id) == SANE_STATUS_GOOD))
{
DBG(DL_MINOR_INFO,
"%s: looking up scanner for ID 0x%04x,0x%04x.\n",
me, vendor_id, product_id);
for (i = 0; i < known_usb_scanners; i++)
{
if ((usb_scanners[i].vendor_id == vendor_id) &&
(usb_scanners[i].product_id == product_id))
{
model_id = usb_scanners[i].id;
DBG(DL_MINOR_INFO, "%s: scanner identified\n", me);
break;
}
}
}
return model_id;
}
/* a sensible sense handler, courtesy of Franck;
the last argument is expected to be a pointer to the associated
SnapScan_Scanner structure */
static SANE_Status sense_handler (int scsi_fd, u_char * result, void *arg)
{
static char me[] = "sense_handler";
SnapScan_Scanner *pss = (SnapScan_Scanner *) arg;
u_char sense, asc, ascq;
char *sense_str = NULL, *as_str = NULL;
SANE_Status status = SANE_STATUS_GOOD;
DBG (DL_CALL_TRACE, "%s(%ld, %p, %p)\n", me, (long) scsi_fd,
(void *) result, (void *) arg);
sense = result[2] & 0x0f;
asc = result[12];
ascq = result[13];
if (pss)
{
pss->asi1 = result[18];
pss->asi2 = result[19];
}
if ((result[0] & 0x80) == 0)
{
DBG (DL_DATA_TRACE, "%s: sense key is invalid.\n", me);
return SANE_STATUS_GOOD; /* sense key invalid */
} else {
DBG (DL_DATA_TRACE, "%s: sense key: 0x%02x, asc: 0x%02x, ascq: 0x%02x, i1: 0x%02x, i2: 0x%02x\n",
me, sense, asc, ascq, result[18], result[19]);
}
switch (sense)
{
case 0x00:
/* no sense */
sense_str = "No sense.";
DBG (DL_MINOR_INFO, "%s: %s\n", me, sense_str);
break;
case 0x02:
/* not ready */
sense_str = "Not ready.";
DBG (DL_MINOR_INFO, "%s: %s\n", me, sense_str);
if (asc == 0x04 && ascq == 0x01)
{
/* warming up; byte 18 contains remaining seconds */
as_str = "Logical unit is in process of becoming ready.";
DBG (DL_MINOR_INFO, "%s: %s (%d seconds)\n", me, as_str, result[18]);
status = SANE_STATUS_DEVICE_BUSY;
}
break;
case 0x04:
/* hardware error */
sense_str = "Hardware error.";
/* byte 18 and 19 detail the hardware problems */
DBG (DL_MINOR_INFO, "%s: %s (0x%02x, 0x%02x)\n", me, sense_str, result[18],
result[19]);
status = SANE_STATUS_IO_ERROR;
break;
case 0x05:
/* illegal request */
sense_str = "Illegal request.";
DBG (DL_MINOR_INFO, "%s: %s\n", me, sense_str);
if (asc == 0x25 && ascq == 0x00)
{
as_str = "Logical unit not supported.";
DBG (DL_MINOR_INFO, "%s: %s\n", me, as_str);
}
status = SANE_STATUS_IO_ERROR;
break;
case 0x09:
/* process error */
sense_str = "Process error.";
DBG (DL_MINOR_INFO, "%s: %s\n", me, sense_str);
if (asc == 0x00 && ascq == 0x05)
{
/* no documents in ADF */
as_str = "End of data detected.";
DBG (DL_MINOR_INFO, "%s: %s\n", me, as_str);
status = SANE_STATUS_NO_DOCS;
}
else if (asc == 0x3b && ascq == 0x05)
{
/* paper jam in ADF */
as_str = "Paper jam.";
DBG (DL_MINOR_INFO, "%s: %s\n", me, as_str);
status = SANE_STATUS_JAMMED;
}
else if (asc == 0x3b && ascq == 0x09)
{
/* scanning area exceeds end of paper in ADF */
as_str = "Read past end of medium.";
DBG (DL_MINOR_INFO, "%s: %s\n", me, as_str);
status = SANE_STATUS_EOF;
}
break;
case 0x0b:
/* Aborted command */
sense_str = "Aborted Command.";
DBG (DL_MINOR_INFO, "%s: %s\n", me, sense_str);
status = SANE_STATUS_IO_ERROR;
break;
default:
DBG (DL_MINOR_ERROR, "%s: no handling for sense %x.\n", me, sense);
break;
}
if (pss)
{
pss->sense_str = sense_str;
pss->as_str = as_str;
}
return status;
}
static SANE_Status open_scanner (SnapScan_Scanner *pss)
{
SANE_Status status;
DBG (DL_CALL_TRACE, "open_scanner\n");
if (!pss->opens)
{
if(pss->pdev->bus == SCSI)
{
status = sanei_scsi_open (pss->devname, &(pss->fd),
sense_handler, (void *) pss);
}
else
{
status = snapscani_usb_open (pss->devname, &(pss->fd),
sense_handler, (void *) pss);
}
}
else
{
/* already open */
status = SANE_STATUS_GOOD;
}
if (status == SANE_STATUS_GOOD)
pss->opens++;
return status;
}
static void close_scanner (SnapScan_Scanner *pss)
{
static char me[] = "close_scanner";
DBG (DL_CALL_TRACE, "%s\n", me);
if (pss->opens)
{
pss->opens--;
if (!pss->opens)
{
if(pss->pdev->bus == SCSI)
{
sanei_scsi_close (pss->fd);
}
else if(pss->pdev->bus == USB)
{
snapscani_usb_close (pss->fd);
}
} else {
DBG(DL_INFO, "%s: handles left: %d\n,",me, pss->opens);
}
}
}
static SANE_Status snapscan_cmd(SnapScan_Bus bus, int fd, const void *src,
size_t src_size, void *dst, size_t * dst_size)
{
SANE_Status status;
DBG (DL_CALL_TRACE, "snapscan_cmd\n");
if(bus == USB)
{
status = snapscani_usb_cmd(fd, src, src_size, dst, dst_size);
}
else
{
status = sanei_scsi_cmd(fd, src, src_size, dst, dst_size);
}
return status;
}
/* SCSI commands */
#define TEST_UNIT_READY 0x00
#define INQUIRY 0x12
#define SEND 0x2A
#define SET_WINDOW 0x24
#define SCAN 0x1B
#define READ 0x28
#define REQUEST_SENSE 0x03
#define RESERVE_UNIT 0x16
#define RELEASE_UNIT 0x17
#define SEND_DIAGNOSTIC 0x1D
#define OBJECT_POSITION 0x31
#define GET_DATA_BUFFER_STATUS 0x34
#define SCAN_LEN 6
#define READ_LEN 10
/* buffer tools */
static void zero_buf (u_char * buf, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
buf[i] = 0x00;
}
#define BYTE_SIZE 8
static u_short u_char_to_u_short (u_char * pc)
{
u_short r = 0;
r |= pc[0];
r = r << BYTE_SIZE;
r |= pc[1];
return r;
}
static void u_short_to_u_charp (u_short x, u_char * pc)
{
pc[0] = (0xFF00 & x) >> BYTE_SIZE;
pc[1] = (0x00FF & x);
}
static void u_int_to_u_char3p (u_int x, u_char * pc)
{
pc[0] = (0xFF0000 & x) >> 2 * BYTE_SIZE;
pc[1] = (0x00FF00 & x) >> BYTE_SIZE;
pc[2] = (0x0000FF & x);
}
static void u_int_to_u_char4p (u_int x, u_char * pc)
{
pc[0] = (0xFF000000 & x) >> 3 * BYTE_SIZE;
pc[1] = (0x00FF0000 & x) >> 2 * BYTE_SIZE;
pc[2] = (0x0000FF00 & x) >> BYTE_SIZE;
pc[3] = (0x000000FF & x);
}
/* Convert 'STRING ' to 'STRING' by adding 0 after last non-space */
static void remove_trailing_space (char *s)
{
int position;
if (NULL == s)
return;
for (position = strlen (s);
position > 0 && ' ' == s[position - 1];
position--)
{
/* dummy */;
}
s[position] = 0;
}
static void check_range (int *v, SANE_Range r)
{
if (*v < r.min)
*v = r.min;
if (*v > r.max)
*v = r.max;
}
#define INQUIRY_LEN 6
#define INQUIRY_RET_LEN 120
#define INQUIRY_RET_LEN_EPSON 139
#define INQUIRY_RET_LEN_5000 138
#define INQUIRY_VENDOR 8 /* Offset in reply data to vendor name */
#define INQUIRY_PRODUCT 16 /* Offset in reply data to product id */
#define INQUIRY_REV 32 /* Offset in reply data to revision level */
#define INQUIRY_PRL2 36 /* Product Revision Level 2 (AGFA) */
#define INQUIRY_HCFG 37 /* Hardware Configuration (AGFA) */
#define INQUIRY_HWST 40 /* Hardware status */
#define INQUIRY_HWMI 41 /* HARDWARE Model ID */
#define INQUIRY_PIX_PER_LINE 42 /* Pixels per scan line (AGFA) */
#define INQUIRY_BYTE_PER_LINE 44 /* Bytes per scan line (AGFA) */
#define INQUIRY_NUM_LINES 46 /* number of scan lines (AGFA) */
#define INQUIRY_OPT_RES 48 /* optical resolution (AGFA) */
#define INQUIRY_SCAN_SPEED 51 /* scan speed (AGFA) */
#define INQUIRY_EXPTIME1 52 /* exposure time, first digit (AGFA) */
#define INQUIRY_EXPTIME2 53 /* exposure time, second digit (AGFA) */
#define INQUIRY_G2R_DIFF 54 /* green to red difference (AGFA) */
#define INQUIRY_B2R_DIFF 55 /* green to red difference (AGFA) */
#define INQUIRY_FIRMWARE 96 /* firmware date and time (AGFA) */
#define INQUIRY_BYTE_PER_LINE_MSB 132 /* ?? top byte of bytes per scan line - epson 2480 */
#define INQUIRY_EPSON_HCFG 138 /* ?? Hardware configuration (Epson) */
/* a mini-inquiry reads only the first 36 bytes of inquiry data, and
returns the vendor(7 chars) and model(16 chars); vendor and model
must point to character buffers of size at least 8 and 17
respectively */
static SANE_Status mini_inquiry (SnapScan_Bus bus, int fd, char *vendor, char *model)
{
static const char *me = "mini_inquiry";
size_t read_bytes;
char cmd[] = {INQUIRY, 0, 0, 0, 36, 0};
char data[36];
SANE_Status status;
read_bytes = 36;
DBG (DL_CALL_TRACE, "%s\n", me);
status = snapscan_cmd (bus, fd, cmd, sizeof (cmd), data, &read_bytes);
CHECK_STATUS (status, me, "snapscan_cmd");
memcpy (vendor, data + 8, 7);
vendor[7] = 0;
memcpy (model, data + 16, 16);
model[16] = 0;
remove_trailing_space (vendor);
remove_trailing_space (model);
return SANE_STATUS_GOOD;
}
/* TODO: Remove */
static char *snapscani_debug_data(char *str,const SANE_Byte *data, int len) {
char tmpstr[10];
int i;
str[0]=0;
for(i=0; i < (len < 20 ? len : 20); i++) {
sprintf(tmpstr," 0x%02x",((int)data[i]) & 0xff);
if(i%16 == 0 && i != 0)
strcat(str,"\n");
strcat(str,tmpstr);
}
if(i < len)
strcat(str," ...");
return str;
}
static SANE_Status inquiry (SnapScan_Scanner *pss)
{
static const char *me = "inquiry";
char tmpstr[150]; /* TODO: Remove */
SANE_Status status;
switch (pss->pdev->model)
{
case PERFECTION2480:
case PERFECTION3490:
if (pss->firmware_loaded)
pss->read_bytes = INQUIRY_RET_LEN_EPSON;
else
pss->read_bytes = INQUIRY_RET_LEN;
break;
case PRISA5000:
case PRISA5150:
pss->read_bytes = INQUIRY_RET_LEN_5000;
break;
default:
pss->read_bytes = INQUIRY_RET_LEN;
break;
}
zero_buf (pss->cmd, MAX_SCSI_CMD_LEN);
pss->cmd[0] = INQUIRY;
pss->cmd[4] = pss->read_bytes;
DBG (DL_CALL_TRACE, "%s\n", me);
status = snapscan_cmd (pss->pdev->bus,
pss->fd,
pss->cmd,
INQUIRY_LEN,
pss->buf,
&pss->read_bytes);
CHECK_STATUS (status, me, "snapscan_cmd");
/* record current parameters */
{
char exptime[4] = {' ', '.', ' ', 0};
exptime[0] = (char) (pss->buf[INQUIRY_EXPTIME1] + '0');
exptime[2] = (char) (pss->buf[INQUIRY_EXPTIME2] + '0');
pss->ms_per_line = atof (exptime)*(float) pss->buf[INQUIRY_SCAN_SPEED];
DBG (DL_DATA_TRACE, "%s: exposure time: %s ms\n", me, exptime);
DBG (DL_DATA_TRACE, "%s: ms per line: %f\n", me, pss->ms_per_line);
}
switch (pss->pdev->model)
{
case SNAPSCAN:
case ACER300F:
pss->chroma_offset[R_CHAN] =
pss->chroma_offset[G_CHAN] =
pss->chroma_offset[B_CHAN] = 0;
pss->chroma = 0;
break;
case PERFECTION2480:
case PERFECTION3490:
if (pss->firmware_loaded)
{
snapscani_debug_data(tmpstr, pss->buf+120, 19);
DBG (DL_DATA_TRACE, "%s: Epson additional inquiry data:\n%s\n", me, tmpstr);
pss->hconfig_epson = pss->buf[INQUIRY_EPSON_HCFG];
}
/* fall through */
default:
{
signed char min_diff;
u_char r_off, g_off, b_off;
signed char g = (pss->buf[INQUIRY_G2R_DIFF] & 0x80) ? -(pss->buf[INQUIRY_G2R_DIFF] & 0x7F) : pss->buf[INQUIRY_G2R_DIFF];
signed char b = (pss->buf[INQUIRY_B2R_DIFF] & 0x80) ? -(pss->buf[INQUIRY_B2R_DIFF] & 0x7F) : pss->buf[INQUIRY_B2R_DIFF];
DBG (DL_DATA_TRACE, "%s: G2R_DIFF: %d\n", me, pss->buf[INQUIRY_G2R_DIFF]);
DBG (DL_DATA_TRACE, "%s: B2R_DIFF: %d\n", me, pss->buf[INQUIRY_B2R_DIFF]);
min_diff = MIN (MIN (b, g), 0);
r_off = (u_char) (0 - min_diff);
g_off = (u_char) (g - min_diff);
b_off = (u_char) (b - min_diff);
pss->chroma_offset[R_CHAN] = r_off;
pss->chroma_offset[G_CHAN] = g_off;
pss->chroma_offset[B_CHAN] = b_off;
pss->chroma = MAX(MAX(r_off, g_off), b_off);
DBG (DL_DATA_TRACE,
"%s: Chroma offsets=%d; Red=%u, Green:=%u, Blue=%u\n",
me, pss->chroma,
pss->chroma_offset[R_CHAN],
pss->chroma_offset[G_CHAN],
pss->chroma_offset[B_CHAN]);
}
break;
}
pss->actual_res =
u_char_to_u_short (pss->buf + INQUIRY_OPT_RES);
pss->pixels_per_line =
u_char_to_u_short (pss->buf + INQUIRY_PIX_PER_LINE);
pss->bytes_per_line =
u_char_to_u_short (pss->buf + INQUIRY_BYTE_PER_LINE);
if ((pss->pdev->model == PERFECTION2480) || (pss->pdev->model == PERFECTION3490))
pss->bytes_per_line += pss->buf[INQUIRY_BYTE_PER_LINE_MSB] << 16;
pss->lines =
u_char_to_u_short (pss->buf + INQUIRY_NUM_LINES) - pss->chroma;
/* effective buffer size must be a whole number of scan lines */
if (pss->lines)
pss->buf_sz = (pss->phys_buf_sz/pss->bytes_per_line)*pss->bytes_per_line;
else
pss->buf_sz = 0;
pss->bytes_remaining = pss->bytes_per_line * (pss->lines + pss->chroma);
pss->expected_read_bytes = 0;
pss->read_bytes = 0;
pss->hwst = pss->buf[INQUIRY_HWST];
if ((pss->pdev->bus == USB) && !(pss->hwst & 0x02))
{
pss->firmware_loaded = SANE_TRUE;
}
pss->hconfig = pss->buf[INQUIRY_HCFG];
switch (pss->pdev->model)
{
case PERFECTION1270:
case PERFECTION1670:
case PERFECTION2480:
case PERFECTION3490:
case PRISA5150:
case PRISA5000:
pss->bpp = 14;
break;
case STYLUS_CX1500:
case SCANWIT2720S:
pss->bpp = 12;
break;
default:
pss->bpp = 8;
if (pss->hconfig & HCFG_ADC)
pss->bpp = 10;
break;
}
DBG (DL_DATA_TRACE,
"%s: hardware config = 0x%02x\n",
me,
pss->hconfig);
DBG (DL_DATA_TRACE,
"%s: bits per pixel = %lu\n",
me,
(u_long) pss->bpp);
DBG (DL_DATA_TRACE,
"%s: pixels per scan line = %lu\n",
me,
(u_long) pss->pixels_per_line);
DBG (DL_DATA_TRACE,
"%s: bytes per scan line = %lu\n",
me,
(u_long) pss->bytes_per_line);
DBG (DL_DATA_TRACE,
"%s: number of scan lines = %lu\n",
me,
(u_long) pss->lines);
DBG (DL_DATA_TRACE,
"%s: effective buffer size = %lu bytes, %lu lines\n",
me,
(u_long) pss->buf_sz,
(u_long) (pss->lines ? pss->buf_sz / pss->lines : 0));
DBG (DL_DATA_TRACE,
"%s: expected total scan data: %lu bytes\n",
me,
(u_long) pss->bytes_remaining);
return status;
}
static SANE_Status test_unit_ready (SnapScan_Scanner *pss)
{
static const char *me = "test_unit_ready";
char cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
SANE_Status status;
DBG (DL_CALL_TRACE, "%s\n", me);
status = snapscan_cmd (pss->pdev->bus, pss->fd, cmd, sizeof (cmd), NULL, NULL);
CHECK_STATUS (status, me, "snapscan_cmd");
return status;
}
static void reserve_unit (SnapScan_Scanner *pss)
{
static const char *me = "reserve_unit";
char cmd[] = {RESERVE_UNIT, 0, 0, 0, 0, 0};
SANE_Status status;
DBG (DL_CALL_TRACE, "%s\n", me);
status = snapscan_cmd (pss->pdev->bus, pss->fd, cmd, sizeof (cmd), NULL, NULL);
if (status != SANE_STATUS_GOOD)
{
DBG (DL_MAJOR_ERROR,
"%s: scsi command error: %s\n",
me,
sane_strstatus (status));
}
}
static void release_unit (SnapScan_Scanner *pss)
{
static const char *me = "release_unit";
char cmd[] = {RELEASE_UNIT, 0, 0, 0, 0, 0};
SANE_Status status;
DBG (DL_CALL_TRACE, "%s\n", me);
status = snapscan_cmd (pss->pdev->bus, pss->fd, cmd, sizeof (cmd), NULL, NULL);
if (status != SANE_STATUS_GOOD)
{
DBG (DL_MAJOR_ERROR,
"%s: scsi command error: %s\n",
me, sane_strstatus (status));
}
}
#define SEND_LENGTH 10
#define DTC_HALFTONE 0x02
#define DTC_GAMMA 0x03
#define DTC_GAMMA2 0x04
#define DTC_SPEED 0x81
#define DTC_CALIBRATION 0x82
#define DTC_CALIBRATION_BLACK 0x89
#define DTCQ_HALFTONE_BW8 0x00
#define DTCQ_HALFTONE_COLOR8 0x01
#define DTCQ_HALFTONE_BW16 0x80
#define DTCQ_HALFTONE_COLOR16 0x81
#define DTCQ_GAMMA_GRAY8 0x00
#define DTCQ_GAMMA_RED8 0x01
#define DTCQ_GAMMA_GREEN8 0x02
#define DTCQ_GAMMA_BLUE8 0x03
#define DTCQ_GAMMA_GRAY10 0x80
#define DTCQ_GAMMA_RED10 0x81
#define DTCQ_GAMMA_GREEN10 0x82
#define DTCQ_GAMMA_BLUE10 0x83
#define DTCQ_GAMMA_GRAY12 0x90
#define DTCQ_GAMMA_RED12 0x91
#define DTCQ_GAMMA_GREEN12 0x92
#define DTCQ_GAMMA_BLUE12 0x93
#define DTCQ_GAMMA_GRAY14 0x95 /* ? */
#define DTCQ_GAMMA_RED14 0x96
#define DTCQ_GAMMA_GREEN14 0x97
#define DTCQ_GAMMA_BLUE14 0x98
#define DTCQ_GAMMA_GRAY12_16BIT 0xa0
#define DTCQ_GAMMA_RED12_16BIT 0xa1
#define DTCQ_GAMMA_GREEN12_16BIT 0xa2
#define DTCQ_GAMMA_BLUE12_16BIT 0xa3
#define DTCQ_GAMMA_GRAY14_16BIT 0xa5 /* ? */
#define DTCQ_GAMMA_RED14_16BIT 0xa6
#define DTCQ_GAMMA_GREEN14_16BIT 0xa7
#define DTCQ_GAMMA_BLUE14_16BIT 0xa8
static SANE_Status send (SnapScan_Scanner *pss, u_char dtc, u_char dtcq)
{
static char me[] = "send";
SANE_Status status;
u_short tl; /* transfer length */
DBG (DL_CALL_TRACE, "%s\n", me);
zero_buf (pss->buf, SEND_LENGTH);
switch (dtc)
{
case DTC_HALFTONE: /* halftone mask */
switch (dtcq)
{
case DTCQ_HALFTONE_BW8:
tl = 64; /* bw 8x8 table */
break;
case DTCQ_HALFTONE_COLOR8:
tl = 3 * 64; /* rgb 8x8 tables */
break;
case DTCQ_HALFTONE_BW16:
tl = 256; /* bw 16x16 table */
break;
case DTCQ_HALFTONE_COLOR16:
tl = 3 * 256; /* rgb 16x16 tables */
break;
default:
DBG (DL_MAJOR_ERROR, "%s: bad halftone data type qualifier 0x%x\n",
me, dtcq);
return SANE_STATUS_INVAL;
}
break;
case DTC_GAMMA: /* gamma function */
case DTC_GAMMA2:
switch (dtcq)
{
case DTCQ_GAMMA_GRAY8: /* 8-bit tables */
case DTCQ_GAMMA_RED8:
case DTCQ_GAMMA_GREEN8:
case DTCQ_GAMMA_BLUE8:
tl = 256;
break;
case DTCQ_GAMMA_GRAY10: /* 10-bit tables */
case DTCQ_GAMMA_RED10:
case DTCQ_GAMMA_GREEN10:
case DTCQ_GAMMA_BLUE10:
tl = 1024;
break;
case DTCQ_GAMMA_GRAY12: /* 12-bit tables */
case DTCQ_GAMMA_RED12:
case DTCQ_GAMMA_GREEN12:
case DTCQ_GAMMA_BLUE12:
tl = 4096;
break;
case DTCQ_GAMMA_GRAY12_16BIT: /* 12-bit tables with 16 bit data */
case DTCQ_GAMMA_RED12_16BIT:
case DTCQ_GAMMA_GREEN12_16BIT:
case DTCQ_GAMMA_BLUE12_16BIT:
tl = 8192;
break;
case DTCQ_GAMMA_GRAY14: /* 14-bit tables */
case DTCQ_GAMMA_RED14:
case DTCQ_GAMMA_GREEN14:
case DTCQ_GAMMA_BLUE14:
tl = 16384;
break;
case DTCQ_GAMMA_GRAY14_16BIT: /* 14-bit tables with 16 bit data */
case DTCQ_GAMMA_RED14_16BIT:
case DTCQ_GAMMA_GREEN14_16BIT:
case DTCQ_GAMMA_BLUE14_16BIT:
tl = 32768;
break;
default:
DBG (DL_MAJOR_ERROR, "%s: bad gamma data type qualifier 0x%x\n",
me, dtcq);
return SANE_STATUS_INVAL;
}
break;
case DTC_SPEED: /* static transfer speed */
tl = 2;
break;
case DTC_CALIBRATION:
tl = calibration_line_length(pss);
break;
default:
DBG (DL_MAJOR_ERROR, "%s: unsupported data type code 0x%x\n",
me, (unsigned) dtc);
return SANE_STATUS_INVAL;
}
pss->buf[0] = SEND;
pss->buf[2] = dtc;
pss->buf[5] = dtcq;
pss->buf[7] = (tl >> 8) & 0xff;
pss->buf[8] = tl & 0xff;
status = snapscan_cmd (pss->pdev->bus, pss->fd, pss->buf, SEND_LENGTH + tl,
NULL, NULL);
CHECK_STATUS (status, me, "snapscan_cmd");
return status;
}
#include "snapscan-data.c"
static SANE_Status send_calibration_5150(SnapScan_Scanner *pss)
{
static const int length = sizeof(calibration_data_5150);
SANE_Byte* buf = malloc (length + SEND_LENGTH);
SANE_Status status;
zero_buf (buf, SEND_LENGTH);
*buf = SEND;
*(buf + 2) = DTC_CALIBRATION;
*(buf + 6) = (length >> 16) & 0xff;
*(buf + 7) = (length >> 8) & 0xff;
*(buf + 8) = length & 0xff;
memcpy(buf + SEND_LENGTH, calibration_data_5150, length);
status = snapscan_cmd (
pss->pdev->bus, pss->fd, buf, SEND_LENGTH + length, NULL, NULL);
free (buf);
return status;
}
#define SET_WINDOW_LEN 10
#define SET_WINDOW_HEADER 10 /* header starts */
#define SET_WINDOW_HEADER_LEN 8
#define SET_WINDOW_DESC 18 /* window descriptor starts */
#define SET_WINDOW_DESC_LEN 48
#define SET_WINDOW_TRANSFER_LEN 56
#define SET_WINDOW_TOTAL_LEN 66
#define SET_WINDOW_RET_LEN 0 /* no returned data */
#define SET_WINDOW_P_TRANSFER_LEN 6
#define SET_WINDOW_P_DESC_LEN 6
#define SET_WINDOW_P_WIN_ID 0
#define SET_WINDOW_P_XRES 2
#define SET_WINDOW_P_YRES 4
#define SET_WINDOW_P_TLX 6
#define SET_WINDOW_P_TLY 10
#define SET_WINDOW_P_WIDTH 14
#define SET_WINDOW_P_LENGTH 18
#define SET_WINDOW_P_BRIGHTNESS 22
#define SET_WINDOW_P_THRESHOLD 23
#define SET_WINDOW_P_CONTRAST 24
#define SET_WINDOW_P_COMPOSITION 25
#define SET_WINDOW_P_BITS_PER_PIX 26
#define SET_WINDOW_P_HALFTONE_PATTERN 27
#define SET_WINDOW_P_PADDING_TYPE 29
#define SET_WINDOW_P_BIT_ORDERING 30
#define SET_WINDOW_P_COMPRESSION_TYPE 32
#define SET_WINDOW_P_COMPRESSION_ARG 33
#define SET_WINDOW_P_HALFTONE_FLAG 35
#define SET_WINDOW_P_DEBUG_MODE 40
#define SET_WINDOW_P_GAMMA_NO 41
#define SET_WINDOW_P_OPERATION_MODE 42
#define SET_WINDOW_P_RED_UNDER_COLOR 43
#define SET_WINDOW_P_BLUE_UNDER_COLOR 45
#define SET_WINDOW_P_GREEN_UNDER_COLOR 44
static SANE_Status prepare_set_window (SnapScan_Scanner *pss)
{
static const char *me = "prepare_set_window";
u_char *pc;
DBG (DL_CALL_TRACE, "%s\n", me);
zero_buf (pss->cmd, MAX_SCSI_CMD_LEN);
/* basic command */
pc = pss->cmd;
pc[0] = SET_WINDOW;
u_int_to_u_char3p ((u_int) SET_WINDOW_TRANSFER_LEN,
pc + SET_WINDOW_P_TRANSFER_LEN);
/* header; we support only one window */
pc += SET_WINDOW_LEN;
u_short_to_u_charp (SET_WINDOW_DESC_LEN, pc + SET_WINDOW_P_DESC_LEN);
/* the sole window descriptor */
pc += SET_WINDOW_HEADER_LEN;
pc[SET_WINDOW_P_WIN_ID] = 0;
u_short_to_u_charp (pss->res, pc + SET_WINDOW_P_XRES);
u_short_to_u_charp (pss->res, pc + SET_WINDOW_P_YRES);
DBG (DL_CALL_TRACE, "%s Resolution: %d\n", me, pss->res);
pc[SET_WINDOW_P_BRIGHTNESS] = 128;
pc[SET_WINDOW_P_THRESHOLD] =
(u_char) (255.0*(pss->threshold / 100.0));
pc[SET_WINDOW_P_CONTRAST] = 128;
{
SnapScan_Mode mode = pss->mode;
pss->bpp_scan = pss->val[OPT_BIT_DEPTH].w;
if (pss->preview)
{
mode = pss->preview_mode;
if (pss->pdev->model != SCANWIT2720S)
pss->bpp_scan = 8;
}
DBG (DL_MINOR_INFO, "%s Mode: %d\n", me, mode);
switch (mode)
{
case MD_COLOUR:
pc[SET_WINDOW_P_COMPOSITION] = 0x05; /* multi-level RGB */
break;
case MD_BILEVELCOLOUR:
if (pss->halftone)
pc[SET_WINDOW_P_COMPOSITION] = 0x04; /* halftone RGB */
else
pc[SET_WINDOW_P_COMPOSITION] = 0x03; /* bi-level RGB */
pss->bpp_scan = 1;
break;
case MD_GREYSCALE:
pc[SET_WINDOW_P_COMPOSITION] = 0x02; /* grayscale */
break;
case MD_LINEART:
if (pss->halftone)
pc[SET_WINDOW_P_COMPOSITION] = 0x01; /* b&w halftone */
else
pc[SET_WINDOW_P_COMPOSITION] = 0x00; /* b&w (lineart) */
pss->bpp_scan = 1;
break;
default:
break;
}
pc[SET_WINDOW_P_BITS_PER_PIX] = pss->bpp_scan;
DBG (DL_INFO, "%s: bits-per-pixel set to %d\n", me, (int) pss->bpp_scan);
}
/* the RIF bit is the high bit of the padding type */
pc[SET_WINDOW_P_PADDING_TYPE] = 0x00 /*| (pss->negative ? 0x00 : 0x80) */ ;
pc[SET_WINDOW_P_HALFTONE_PATTERN] = 0;
pc[SET_WINDOW_P_HALFTONE_FLAG] = 0x80; /* always set; image
composition
determines whether
halftone is
actually used */
u_short_to_u_charp (0x0000, pc + SET_WINDOW_P_BIT_ORDERING); /* used? */
pc[SET_WINDOW_P_COMPRESSION_TYPE] = 0; /* none */
pc[SET_WINDOW_P_COMPRESSION_ARG] = 0; /* none applicable */
if(pss->pdev->model != ACER300F
&&
pss->pdev->model != SNAPSCAN310
&&
pss->pdev->model != PRISA310
&&
pss->pdev->model != PRISA610
) {
pc[SET_WINDOW_P_DEBUG_MODE] = 2; /* use full 128k buffer */
if (pss->mode != MD_LINEART)
{
pc[SET_WINDOW_P_GAMMA_NO] = 0x01; /* downloaded gamma table */
}
}
pc[SET_WINDOW_P_RED_UNDER_COLOR] = 0xff; /* defaults */
pc[SET_WINDOW_P_BLUE_UNDER_COLOR] = 0xff;
pc[SET_WINDOW_P_GREEN_UNDER_COLOR] = 0xff;
return SANE_STATUS_GOOD;
}
static SANE_Status set_window (SnapScan_Scanner *pss)
{
static const char *me = "set_window";
SANE_Status status;
unsigned char source;
u_char *pc;
int pos_factor;
DBG (DL_CALL_TRACE, "%s\n", me);
status = prepare_set_window(pss);
CHECK_STATUS (status, me, "prepare_set_window");
pc = pss->cmd;
/* header; we support only one window */
pc += SET_WINDOW_LEN;
/* the sole window descriptor */
pc += SET_WINDOW_HEADER_LEN;
switch (pss->pdev->model)
{
case PRISA5000:
case PRISA5000E:
case PRISA5150:
pos_factor = (pss->res > 600) ? 1200 : 600;
break;
case PERFECTION1270:
case PERFECTION1670:
pos_factor = (pss->res > 800) ? 1600 : 800;
break;
case PERFECTION2480:
pos_factor = (pss->res > 1200) ? 2400 : 1200;
break;
case PERFECTION3490:
pos_factor = (pss->res > 1600) ? 3200 : 1600;
break;
default:
pos_factor = pss->actual_res;
break;
}
/* it's an ugly sound if the scanner drives against the rear
wall, and with changing max values we better be sure */
check_range(&(pss->brx), pss->pdev->x_range);
check_range(&(pss->bry), pss->pdev->y_range);
{
int tlxp =
(int) (pos_factor*IN_PER_MM*SANE_UNFIX(pss->tlx));
int tlyp =
(int) (pos_factor*IN_PER_MM*SANE_UNFIX(pss->tly));
int brxp =
(int) (pos_factor*IN_PER_MM*SANE_UNFIX(pss->brx));
int bryp =
(int) (pos_factor*IN_PER_MM*SANE_UNFIX(pss->bry));
/* Check for brx > tlx and bry > tly */
if (brxp <= tlxp) {
tlxp = MAX (0, brxp - 75);
}
if (bryp <= tlyp) {
tlyp = MAX (0, bryp - 75);
}
u_int_to_u_char4p (tlxp, pc + SET_WINDOW_P_TLX);
u_int_to_u_char4p (tlyp, pc + SET_WINDOW_P_TLY);
u_int_to_u_char4p (MAX (((unsigned) (brxp - tlxp)), 75),
pc + SET_WINDOW_P_WIDTH);
u_int_to_u_char4p (MAX (((unsigned) (bryp - tlyp)), 75),
pc + SET_WINDOW_P_LENGTH);
DBG (DL_INFO, "%s Width: %d\n", me, brxp-tlxp);
DBG (DL_INFO, "%s Length: %d\n", me, bryp-tlyp);
}
source = 0x0;
if (pss->preview) {
source |= 0x80; /* no high quality in preview */
}
else {
source |= 0x40; /* no preview */
}
if (!pss->highquality) {
source |= 0x80; /* no high quality */
}
if ((pss->pdev->model == PERFECTION2480) || (pss->pdev->model == PERFECTION3490)) {
source |= 0x40; /* 2480/3490 always need no_preview bit */
}
if (pss->source == SRC_TPO) {
source |= 0x08;
}
if (pss->source == SRC_ADF) {
source |= 0x10;
}
pc[SET_WINDOW_P_OPERATION_MODE] = source;
DBG (DL_MINOR_INFO, "%s: operation mode set to 0x%02x\n", me, (int) source);
do {
status = snapscan_cmd (pss->pdev->bus, pss->fd, pss->cmd,
SET_WINDOW_TOTAL_LEN, NULL, NULL);
if (status == SANE_STATUS_DEVICE_BUSY) {
DBG (DL_MINOR_INFO, "%s: waiting for scanner to warm up\n", me);
wait_scanner_ready (pss);
}
} while (status == SANE_STATUS_DEVICE_BUSY);
CHECK_STATUS (status, me, "snapscan_cmd");
return status;
}
static SANE_Status set_window_autofocus (SnapScan_Scanner *copy)
{
static char me[] = "set_window_autofocus";
SANE_Status status;
DBG (DL_CALL_TRACE, "%s(%p)\n", me, (void*)copy);
copy->res = copy->actual_res;
status = prepare_set_window (copy);
CHECK_STATUS (status, me, "prepare_set_window");
u_int_to_u_char4p (1700, copy->cmd + SET_WINDOW_DESC + SET_WINDOW_P_TLY);
/* fill in width & height */
u_int_to_u_char4p (2550, copy->cmd + SET_WINDOW_DESC + SET_WINDOW_P_WIDTH);
u_int_to_u_char4p (128, copy->cmd + SET_WINDOW_DESC + SET_WINDOW_P_LENGTH);
copy->cmd[SET_WINDOW_DESC + SET_WINDOW_P_BITS_PER_PIX] = 12;
copy->cmd[SET_WINDOW_DESC + SET_WINDOW_P_OPERATION_MODE] = 0x49; /* focusing mode */
return snapscan_cmd (copy->pdev->bus, copy->fd, copy->cmd,
SET_WINDOW_TOTAL_LEN, NULL, NULL);
}
#define SET_FRAME_LEN 10
static SANE_Status set_frame (SnapScan_Scanner *pss, SANE_Byte frame_no)
{
static const char *me = "set_frame";
SANE_Status status;
DBG (DL_CALL_TRACE, "%s\n", me);
DBG (DL_VERBOSE, "%s setting frame to %d\n", me, frame_no);
zero_buf (pss->cmd, MAX_SCSI_CMD_LEN);
pss->cmd[0] = OBJECT_POSITION;
pss->cmd[1] = 2; /* Absolute position used here to select the frame */
pss->cmd[4] = frame_no;
status = snapscan_cmd (pss->pdev->bus, pss->fd, pss->cmd, SET_FRAME_LEN, NULL, NULL);
CHECK_STATUS (status, me, "snapscan_cmd");
return status;
}
static SANE_Status set_focus (SnapScan_Scanner *pss, SANE_Int focus)
{
static const char *me = "set_focus";
SANE_Status status;
DBG (DL_CALL_TRACE, "%s(%d)\n", me, focus);
zero_buf (pss->cmd, MAX_SCSI_CMD_LEN);
pss->cmd[0] = OBJECT_POSITION;
pss->cmd[1] = 4; /* Rotate object but here it sets the focus point */
pss->cmd[3] = (focus >> 8) & 0xFF;
pss->cmd[4] = focus & 0xFF;
status = snapscan_cmd (pss->pdev->bus, pss->fd, pss->cmd, SET_FRAME_LEN, NULL, NULL);
CHECK_STATUS (status, me, "snapscan_cmd");
return status;
}
static SANE_Int get_8 (u_char *p)
{
SANE_Int b;
b = p[0] | (p[1] << 8);
return b;
}
static double get_val (u_char *p, SANE_Int len, SANE_Int x)
{
return get_8 (p + ((x + len) << 1)) / 255.0;
}
static double sum_pixel_differences (u_char *p, int len)
{
double v, m, s;
SANE_Int i;
s = 0;
for (i = 0; i < len-1; i++) {
v = get_val (p, len, i);
m = get_val (p, len, i+1);
s += fabs (v - m);
}
return s;
}
static SANE_Status scan (SnapScan_Scanner *pss)
{
static const char *me = "scan";
SANE_Status status;
DBG (DL_CALL_TRACE, "%s\n", me);
zero_buf (pss->cmd, MAX_SCSI_CMD_LEN);
pss->cmd[0] = SCAN;
status = snapscan_cmd (pss->pdev->bus, pss->fd, pss->cmd, SCAN_LEN, NULL, NULL);
CHECK_STATUS (status, me, "snapscan_cmd");
return status;
}
/* supported read operations */
#define READ_IMAGE 0x00
#define READ_TRANSTIME 0x80
/* number of bytes expected must be in pss->expected_read_bytes */
static SANE_Status scsi_read (SnapScan_Scanner *pss, u_char read_type)
{
static const char *me = "scsi_read";
SANE_Status status;
DBG (DL_CALL_TRACE, "%s\n", me);
zero_buf (pss->cmd, MAX_SCSI_CMD_LEN);
pss->cmd[0] = READ;
pss->cmd[2] = read_type;
if (read_type == READ_TRANSTIME && pss->pdev->model == PERFECTION2480)
pss->cmd[5] = 1;
u_int_to_u_char3p (pss->expected_read_bytes, pss->cmd + 6);
pss->read_bytes = pss->expected_read_bytes;
status = snapscan_cmd (pss->pdev->bus, pss->fd, pss->cmd,
READ_LEN, pss->buf, &pss->read_bytes);
CHECK_STATUS (status, me, "snapscan_cmd");
return status;
}
static SANE_Status get_focus (SnapScan_Scanner *pss)
{
static const char *me = "get_focus";
SANE_Int focus_point, max_focus_point;
double sum, max;
SANE_Status status;
SnapScan_Scanner copy;
copy = *pss;
DBG (DL_CALL_TRACE, "%s\n", me);
reserve_unit(&copy);
status = set_window_autofocus (&copy);
CHECK_STATUS (status, me, "set_window_autofocus");
status = inquiry (&copy);
CHECK_STATUS (status, me, "inquiry");
status = scan (&copy);
CHECK_STATUS (status, me, "scan");
status = set_frame (&copy, copy.frame_no);
CHECK_STATUS (status, me, "set_frame");
DBG (DL_VERBOSE, "%s: Expected number of bytes for each read %d\n", me, (int)copy.bytes_per_line);
DBG (DL_VERBOSE, "%s: Expected number of pixels per line %d\n", me, (int)copy.pixels_per_line);
max_focus_point = -1;
max = -1;
for (focus_point = 0; focus_point <= 0x300; focus_point += 6) {
status = set_focus (&copy, focus_point);
CHECK_STATUS (status, me, "set_focus");
copy.expected_read_bytes = copy.bytes_per_line;
status = scsi_read (&copy, READ_IMAGE);
CHECK_STATUS (status, me, "scsi_read");
sum = sum_pixel_differences (copy.buf, copy.pixels_per_line);
if (sum > max) {
max = sum;
max_focus_point = focus_point;
}
}
pss->focus = max_focus_point;
DBG (DL_VERBOSE, "%s: Focus point found to be at 0x%x\n", me, max_focus_point);
release_unit (&copy);
wait_scanner_ready (&copy);
CHECK_STATUS (status, me, "wait_scanner_ready");
return status;
}
/*
static SANE_Status request_sense (SnapScan_Scanner *pss)
{
static const char *me = "request_sense";
size_t read_bytes = 0;
u_char cmd[] = {REQUEST_SENSE, 0, 0, 0, 20, 0};
u_char data[20];
SANE_Status status;
read_bytes = 20;
DBG (DL_CALL_TRACE, "%s\n", me);
status = snapscan_cmd (pss->pdev->bus, pss->fd, cmd, sizeof (cmd),
data, &read_bytes);
if (status != SANE_STATUS_GOOD)
{
DBG (DL_MAJOR_ERROR, "%s: scsi command error: %s\n",
me, sane_strstatus (status));
}
else
{
status = sense_handler (pss->fd, data, (void *) pss);
}
return status;
}
*/
static SANE_Status send_diagnostic (SnapScan_Scanner *pss)
{
static const char *me = "send_diagnostic";
u_char cmd[] = {SEND_DIAGNOSTIC, 0x04, 0, 0, 0, 0}; /* self-test */
SANE_Status status;
if (pss->pdev->model == PRISA620
||
pss->pdev->model == PRISA610
||
pss->pdev->model == SNAPSCAN1236
||
pss->pdev->model == SCANWIT2720S
||
pss->pdev->model == ARCUS1200)
{
return SANE_STATUS_GOOD;
}
DBG (DL_CALL_TRACE, "%s\n", me);
status = snapscan_cmd (pss->pdev->bus, pss->fd, cmd, sizeof (cmd), NULL, NULL);
CHECK_STATUS (status, me, "snapscan_cmd");
return status;
}
static SANE_Status wait_scanner_ready (SnapScan_Scanner *pss)
{
static char me[] = "wait_scanner_ready";
SANE_Status status;
int retries;
DBG (DL_CALL_TRACE, "%s\n", me);
/* if the tray is returning to the start position
no time to wait is returned by the scanner. We'll
try several times and sleep 1 second between each try. */
for (retries = 20; retries; retries--)
{
status = test_unit_ready (pss);
switch (status)
{
case SANE_STATUS_GOOD:
return status;
case SANE_STATUS_DEVICE_BUSY:
/* first additional sense byte contains time to wait */
{
int delay = pss->asi1;
if (delay > 0)
{
DBG (0,
"Scanner warming up - waiting %d seconds.\n",
delay);
sleep (delay);
}
else
{
/* This seems to happen for Epson scanners. Return
SANE_STATUS_GOOD and hope the scanner accepts the
next command... */
DBG (DL_CALL_TRACE, "%s: No timeout specified, returning immediately\n", me);
return SANE_STATUS_GOOD;
}
}
break;
case SANE_STATUS_IO_ERROR:
/* hardware error; bail */
DBG (DL_MAJOR_ERROR, "%s: hardware error detected.\n", me);
return status;
case SANE_STATUS_JAMMED:
case SANE_STATUS_NO_DOCS:
return status;
default:
DBG (DL_MAJOR_ERROR,
"%s: unhandled request_sense result; trying again.\n",
me);
break;
}
}
return status;
}
#define READ_CALIBRATION 0x82
#define READ_CALIBRATION_BLACK 0x89
#define NUM_CALIBRATION_LINES 16
#define NUM_CALIBRATION_LINES_EPSON 48
#define NUM_CALIBRATION_LINES_EPSON_BLACK 128
static SANE_Status calibrate_epson (SnapScan_Scanner *pss)
{
u_char *buf, *pbuf;
int *bins;
static const char *me = "calibrate_epson";
/* pixels_per_line = 8.5 inch * resolution of one sensor */
int pixels_per_line = pss->actual_res * 17/4;
int num_bins = pixels_per_line;
int i, j, k, loop_inc, tl;
int r, g, b;
size_t expected_read_bytes;
size_t read_bytes;
SANE_Status status;
int pass;
int cal_lines = NUM_CALIBRATION_LINES_EPSON;
int dtc = READ_CALIBRATION;
int bytes_per_bin = 1;
/* in 16 bit mode we get two bytes of cal data per bin */
if (pss->bpp_scan == 16)
bytes_per_bin = 2;
/* calculate number of bins depending on mode and resolution
* colour mode requires bins for each of rgb
* full resolution doubles it because of second sensor line */
if (is_colour_mode(actual_mode(pss))) {
num_bins *= 3;
}
if (pss->res >= (SANE_Int)pss->actual_res) {
num_bins *= 2;
}
/* allocate memory for bins, all the red, then green, then blue */
bins = (int *) malloc (num_bins * sizeof (int));
if (!bins) {
DBG (DL_MAJOR_ERROR, "%s: out of memory allocating bins, %ld bytes.", me, (u_long)num_bins * sizeof (int));
return SANE_STATUS_NO_MEM;
}
/* allocate buffer for receive data */
expected_read_bytes = pixels_per_line * 3 * 4;
buf = (u_char *) malloc (expected_read_bytes);
if (!buf) {
DBG (DL_MAJOR_ERROR, "%s: out of memory allocating calibration, %ld bytes.", me, (u_long)expected_read_bytes);
free (bins);
return SANE_STATUS_NO_MEM;
}
loop_inc = expected_read_bytes / (num_bins * bytes_per_bin);
/* do two passes, first pass does basic calibration, second does transparency adaptor if in use */
for (pass = 0; pass < 2; pass++) {
if (pass == 1) {
if (pss->source == SRC_TPO) {
/* pass 1 is for black level calibration of transparency adaptor */
cal_lines = NUM_CALIBRATION_LINES_EPSON_BLACK;
dtc = READ_CALIBRATION_BLACK;
} else
continue;
}
/* empty the bins */
for (i = 0; i < num_bins; i++)
bins[i] = 0;
for (i = 0; i < cal_lines; i += loop_inc) {
/* get the calibration data */
zero_buf (pss->cmd, MAX_SCSI_CMD_LEN);
pss->cmd[0] = READ;
pss->cmd[2] = dtc;
pss->cmd[5] = cal_lines;
if (cal_lines - i > loop_inc)
expected_read_bytes = loop_inc * (num_bins * bytes_per_bin);
else
expected_read_bytes = (cal_lines - i) * (num_bins * bytes_per_bin);
u_int_to_u_char3p (expected_read_bytes, pss->cmd + 6);
read_bytes = expected_read_bytes;
status = snapscan_cmd (pss->pdev->bus, pss->fd, pss->cmd,
READ_LEN, buf, &read_bytes);
if (status != SANE_STATUS_GOOD) {
DBG(DL_MAJOR_ERROR, "%s: %s command failed: %s\n", me, "read_cal_2480", sane_strstatus(status));
free (bins);
free (buf);
return status;
}
if (read_bytes != expected_read_bytes) {
DBG (DL_MAJOR_ERROR, "%s: read %lu of %lu calibration data\n", me, (u_long) read_bytes, (u_long) expected_read_bytes);
free (bins);
free (buf);
return SANE_STATUS_IO_ERROR;
}
/* add calibration results into bins */
pbuf = buf;
for (j = 0; j < (int)expected_read_bytes / (num_bins * bytes_per_bin); j++) {
for (k = 0; k < num_bins; k++) {
bins[k] += *pbuf++;
/* add in second byte for 16bit mode */
if (bytes_per_bin == 2) {
bins[k] += *pbuf++ * 256;
}
}
}
}
/* now make averages */
for (k = 0; k < num_bins; k++) {
bins[k] /= cal_lines;
/* also divide by 64 for 16bit mode */
if (bytes_per_bin == 2)
bins[k] /= 64;
}
/* now fill up result buffer */
r = g = b = 0;
/* create data to send back: start with r g b values, and follow with differences
* to previous value */
pbuf = pss->buf + SEND_LENGTH;
if (is_colour_mode(actual_mode(pss))) {
for (k = 0; k < num_bins / 3; k++) {
*pbuf++ = bins[k] - r;
r = bins[k];
*pbuf++ = bins[k + num_bins/3] - g;
g = bins[k + num_bins/3];
*pbuf++ = bins[k + 2*num_bins/3] - b;
b = bins[k + 2*num_bins/3];
}
} else {
for (k = 0; k < num_bins; k++) {
*pbuf++ = bins[k] - g;
g = bins[k];
}
}
/* send back the calibration data; round up transfer length (to match windows driver) */
zero_buf (pss->buf, SEND_LENGTH);
pss->buf[0] = SEND;
pss->buf[2] = dtc;
tl = (num_bins + 0xff) & ~0xff;
u_int_to_u_char3p (tl, pss->buf + 6);
status = snapscan_cmd (pss->pdev->bus, pss->fd, pss->buf, SEND_LENGTH + tl,
NULL, NULL);
if (status != SANE_STATUS_GOOD) {
DBG(DL_MAJOR_ERROR, "%s: %s command failed: %s\n", me, "send_cal_2480", sane_strstatus(status));
free (bins);
free (buf);
return status;
}
}
free (bins);
free (buf);
return SANE_STATUS_GOOD;
}
static SANE_Status read_calibration_data (SnapScan_Scanner *pss, void *buf, u_char num_lines)
{
static const char *me = "read_calibration_data";
SANE_Status status;
size_t expected_read_bytes = num_lines * calibration_line_length(pss);
size_t read_bytes;
DBG (DL_CALL_TRACE, "%s\n", me);
zero_buf (pss->cmd, MAX_SCSI_CMD_LEN);
pss->cmd[0] = READ;
pss->cmd[2] = READ_CALIBRATION;
pss->cmd[5] = num_lines;
u_int_to_u_char3p (expected_read_bytes, pss->cmd + 6);
read_bytes = expected_read_bytes;
status = snapscan_cmd (pss->pdev->bus, pss->fd, pss->cmd,
READ_LEN, buf, &read_bytes);
CHECK_STATUS (status, me, "snapscan_cmd");
if(read_bytes != expected_read_bytes) {
DBG (DL_MAJOR_ERROR, "%s: read %lu of %lu calibration data\n", me, (u_long) read_bytes, (u_long) expected_read_bytes);
return SANE_STATUS_IO_ERROR;
}
return SANE_STATUS_GOOD;
}
static SANE_Status calibrate (SnapScan_Scanner *pss)
{
int r;
int c;
u_char *buf;
static const char *me = "calibrate";
SANE_Status status;
int line_length = calibration_line_length(pss);
if ((pss->pdev->model == PERFECTION2480) ||
(pss->pdev->model == PERFECTION3490)) {
return calibrate_epson (pss);
}
if (pss->pdev->model == PRISA5150)
{
return send_calibration_5150(pss);
}
DBG (DL_CALL_TRACE, "%s\n", me);
if (line_length) {
int num_lines = pss->phys_buf_sz / line_length;
if (num_lines > NUM_CALIBRATION_LINES)
{
num_lines = NUM_CALIBRATION_LINES;
} else if (num_lines == 0)
{
DBG(DL_MAJOR_ERROR, "%s: scsi request size underflow (< %d bytes)", me, line_length);
return SANE_STATUS_IO_ERROR;
}
buf = (u_char *) malloc(num_lines * line_length);
if (!buf)
{
DBG (DL_MAJOR_ERROR, "%s: out of memory allocating calibration, %d bytes.", me, num_lines * line_length);
return SANE_STATUS_NO_MEM;
}
DBG (DL_MAJOR_ERROR, "%s: reading calibration data (%d lines)\n", me, num_lines);
status = read_calibration_data(pss, buf, num_lines);
CHECK_STATUS(status, me, "read_calibration_data");
for(c=0; c < line_length; c++) {
u_int sum = 0;
for(r=0; r < num_lines; r++) {
sum += buf[c + r * line_length];
}
pss->buf[c + SEND_LENGTH] = sum / num_lines;
}
status = send (pss, DTC_CALIBRATION, 1);
CHECK_STATUS(status, me, "send calibration");
free(buf);
}
return SANE_STATUS_GOOD;
}
static SANE_Status download_firmware(SnapScan_Scanner * pss)
{
static const char *me = "download_firmware";
unsigned char *pFwBuf, *pCDB;
char* firmware = NULL;
FILE *fd;
size_t bufLength,cdbLength;
SANE_Status status = SANE_STATUS_GOOD;
char cModelName[8], cModel[255];
unsigned char bModelNo;
bModelNo =*(pss->buf + INQUIRY_HWMI);
zero_buf((unsigned char *)cModel, 255);
sprintf(cModelName, "%d", bModelNo);
DBG(DL_INFO, "Looking up %s\n", cModelName);
if (pss->pdev->firmware_filename) {
firmware = pss->pdev->firmware_filename;
} else if (default_firmware_filename) {
firmware = default_firmware_filename;
} else {
DBG (0,
"%s: No firmware entry found in config file %s.\n",
me,
SNAPSCAN_CONFIG_FILE
);
status = SANE_STATUS_INVAL;
}
if (status == SANE_STATUS_GOOD)
{
cdbLength = 10;
DBG(DL_INFO, "Downloading %s\n", firmware);
fd = fopen(firmware,"rb");
if(fd == NULL)
{
DBG (0, "Cannot open firmware file %s.\n", firmware);
DBG (0, "Edit the firmware file entry in %s.\n", SNAPSCAN_CONFIG_FILE);
status = SANE_STATUS_INVAL;
}
else
{
switch (pss->pdev->model)
{
case PRISA610:
case PRISA310:
case PRISA620:
case PRISA1240:
case PRISA640:
case PRISA4300:
case PRISA4300_2:
case PRISA5000:
case PRISA5000E:
case PRISA5150:
case PRISA5300:
case STYLUS_CX1500:
/* ACER firmware files do not contain an info block */
fseek(fd, 0, SEEK_END);
bufLength = ftell(fd);
fseek(fd, 0, SEEK_SET);
break;
case PERFECTION1270:
case PERFECTION1670:
case PERFECTION2480:
case PERFECTION3490:
/* Epson firmware files contain an info block which
specifies the length of the firmware data. The
length information is stored at offset 0x64 from
end of file */
{
unsigned char size_l, size_h;
fseek(fd, -0x64, SEEK_END);
fread(&size_l, 1, 1, fd);
fread(&size_h, 1, 1, fd);
fseek(fd, 0, SEEK_SET);
bufLength = (size_h << 8) + size_l;
}
break;
default:
/* AGFA firmware files contain an info block which
specifies the length of the firmware data. The
length information is stored at offset 0x5e from
end of file */
{
unsigned char size_l, size_h;
fseek(fd, -0x5e, SEEK_END);
fread(&size_l, 1, 1, fd);
fread(&size_h, 1, 1, fd);
fseek(fd, 0, SEEK_SET);
bufLength = (size_h << 8) + size_l;
}
break;
}
DBG(DL_INFO, "Size of firmware: %lu\n", (u_long) bufLength);
pCDB = (unsigned char *)malloc(bufLength + cdbLength);
pFwBuf = pCDB + cdbLength;
zero_buf (pCDB, cdbLength);
(void)fread(pFwBuf,1,bufLength,fd);
*pCDB = SEND;
*(pCDB + 2) = 0x87;
*(pCDB + 6) = (bufLength >> 16) & 0xff;
*(pCDB + 7) = (bufLength >> 8) & 0xff;
*(pCDB + 8) = bufLength & 0xff;
status = snapscan_cmd (
pss->pdev->bus, pss->fd, pCDB, bufLength+cdbLength, NULL, NULL);
pss->firmware_loaded = SANE_TRUE;
free(pCDB);
fclose(fd);
}
}
return status;
}
/*
* Revision 1.58 2006/09/03 10:00:11 oliver-guest
* Bugfix for firmware download by Paul Smedley
*
* Revision 1.57 2006/03/20 18:20:10 oliver-guest
* Limit inquiry length to 120 bytes if firmware is not yet loaded
*
* Revision 1.56 2006/01/10 19:32:16 oliver-guest
* Added 12 bit gamma tables for Epson Stylus CX-1500
*
* Revision 1.55 2006/01/06 20:59:17 oliver-guest
* Some fixes for the Epson Stylus CX 1500
*
* Revision 1.54 2006/01/01 22:57:01 oliver-guest
* Added calibration data for Benq 5150 / 5250, preliminary support for Epson Stylus CX 1500
*
* Revision 1.53 2005/12/05 20:38:22 oliver-guest
* Small bugfix for Benq 5150
*
* Revision 1.52 2005/12/04 15:03:00 oliver-guest
* Some fixes for Benq 5150
*
* Revision 1.51 2005/11/26 18:53:03 oliver-guest
* Fix inquiry bug for Benq 5000
*
* Revision 1.50 2005/11/17 23:47:10 oliver-guest
* Revert previous 'fix', disable 2400 dpi for Epson 3490, use 1600 dpi instead
*
* Revision 1.49 2005/11/17 23:32:22 oliver-guest
* Fixes for Epson 3490 @ 2400 DPI
*
* Revision 1.48 2005/11/15 20:11:19 oliver-guest
* Enabled quality calibration for the Epson 3490
*
* Revision 1.47 2005/11/02 19:22:06 oliver-guest
* Fixes for Benq 5000
*
* Revision 1.46 2005/10/31 21:08:47 oliver-guest
* Distinguish between Benq 5000/5000E/5000U
*
* Revision 1.45 2005/10/24 19:46:40 oliver-guest
* Preview and range fix for Epson 2480/2580
*
* Revision 1.44 2005/10/23 21:28:58 oliver-guest
* Fix for buffer size in high res modes, fixes for delay code
*
* Revision 1.43 2005/10/20 21:23:53 oliver-guest
* Fixes for 16 bit quality calibration by Simon Munton
*
* Revision 1.42 2005/10/13 22:43:30 oliver-guest
* Fixes for 16 bit scan mode from Simon Munton
*
* Revision 1.41 2005/10/11 18:47:07 oliver-guest
* Fixes for Epson 3490 and 16 bit scan mode
*
* Revision 1.40 2005/09/28 22:09:26 oliver-guest
* Re-enabled enhanced inquiry command for Epson scanners (duh\!)
*
* Revision 1.39 2005/09/28 21:33:10 oliver-guest
* Added 16 bit option for Epson scanners (untested)
*
* Revision 1.38 2005/09/25 08:19:12 oliver-guest
* Removed debugging code for Epson scanners
*
* Revision 1.37 2005/09/03 11:31:31 oliver-guest
* Another small bugfix
*
* Revision 1.36 2005/09/03 10:52:11 oliver-guest
* Fixed debugging code for epson scanners
*
* Revision 1.35 2005/08/16 17:19:20 oliver-guest
* Make compileable again
*
* Revision 1.34 2005/08/15 18:56:55 oliver-guest
* Added temporary debug code for 2480/2580 distinction
*
* Revision 1.33 2005/08/15 18:06:37 oliver-guest
* Added support for Epson 3490/3590 (thanks to Matt Judge)
*
* Revision 1.32 2005/07/18 17:37:37 oliver-guest
* ZETA changes for SnapScan backend
*
* Revision 1.31 2004/12/09 23:21:48 oliver-guest
* Added quality calibration for Epson 2480 (by Simon Munton)
*
* Revision 1.30 2004/12/01 22:12:03 oliver-guest
* Added support for Epson 1270
*
* Revision 1.29 2004/10/03 17:34:36 hmg-guest
* 64 bit platform fixes (bug #300799).
*
* Revision 1.28 2004/09/02 20:59:11 oliver-guest
* Added support for Epson 2480
*
* Revision 1.27 2004/04/02 20:19:24 oliver-guest
* Various bugfixes for gamma correction (thanks to Robert Tsien)
*
* Revision 1.26 2003/11/07 23:26:49 oliver-guest
* Final bugfixes for bascic support of Epson 1670
*
* Revision 1.25 2003/10/21 20:43:25 oliver-guest
* Bugfixes for SnapScan backend
*
* Revision 1.24 2003/10/07 19:41:34 oliver-guest
* Updates for Epson Perfection 1670
*
* Revision 1.23 2003/08/19 21:05:08 oliverschwartz
* Scanner ID cleanup
*
* Revision 1.22 2003/04/30 20:49:39 oliverschwartz
* SnapScan backend 1.4.26
*
* Revision 1.37 2003/04/30 20:42:19 oliverschwartz
* Added support for Agfa Arcus 1200 (supplied by Valtteri Vuorikoski)
*
* Revision 1.36 2003/04/02 21:17:13 oliverschwartz
* Fix for 1200 DPI with Acer 5000
*
* Revision 1.35 2003/02/08 10:45:09 oliverschwartz
* Use 600 DPI as optical resolution for Benq 5000
*
* Revision 1.34 2002/12/10 20:14:12 oliverschwartz
* Enable color offset correction for SnapScan300
*
* Revision 1.33 2002/09/24 16:07:48 oliverschwartz
* Added support for Benq 5000
*
* Revision 1.32 2002/06/06 20:40:01 oliverschwartz
* Changed default scan area for transparency unit of SnapScan e50
*
* Revision 1.31 2002/05/02 18:28:44 oliverschwartz
* Added ADF support
*
* Revision 1.30 2002/04/27 14:41:22 oliverschwartz
* Print number of open handles in close_scanner()
*
* Revision 1.29 2002/04/10 21:46:48 oliverschwartz
* Removed illegal character
*
* Revision 1.28 2002/04/10 21:01:02 oliverschwartz
* Disable send_diagnostic() for 1236s
*
* Revision 1.27 2002/03/24 12:11:20 oliverschwartz
* Get name of firmware file in sane_init
*
* Revision 1.26 2002/01/23 20:42:41 oliverschwartz
* Improve recognition of Acer 320U
* Add sense_handler code for sense code 0x0b
* Fix for spaces in model strings
*
* Revision 1.25 2001/12/12 19:44:59 oliverschwartz
* Clean up CVS log
*
* Revision 1.24 2001/12/09 23:01:00 oliverschwartz
* - use sense handler for USB
* - fix scan mode
*
* Revision 1.23 2001/12/08 11:53:31 oliverschwartz
* - Additional logging in sense handler
* - Fix wait_scanner_ready() if device reports busy
* - Fix scanning mode (preview/normal)
*
* Revision 1.22 2001/11/27 23:16:17 oliverschwartz
* - Fix color alignment for SnapScan 600
* - Added documentation in snapscan-sources.c
* - Guard against TL_X < BR_X and TL_Y < BR_Y
*
* Revision 1.21 2001/10/21 08:49:37 oliverschwartz
* correct number of scan lines for calibration thanks to Mikko Ty<54><79><EFBFBD>vi
*
* Revision 1.20 2001/10/12 20:54:04 oliverschwartz
* enable gamma correction for Snapscan 1236, e20 and e50 scanners
*
* Revision 1.19 2001/10/11 14:02:10 oliverschwartz
* Distinguish between e20/e25 and e40/e50
*
* Revision 1.18 2001/10/09 22:34:23 oliverschwartz
* fix compiler warnings
*
* Revision 1.17 2001/10/08 19:26:01 oliverschwartz
* - Disable quality calibration for scanners that do not support it
*
* Revision 1.16 2001/10/08 18:22:01 oliverschwartz
* - Disable quality calibration for Acer Vuego 310F
* - Use sanei_scsi_max_request_size as scanner buffer size
* for SCSI devices
* - Added new devices to snapscan.desc
*
* Revision 1.15 2001/09/18 15:01:07 oliverschwartz
* - Read scanner id string again after firmware upload
* to identify correct model
* - Make firmware upload work for AGFA scanners
* - Change copyright notice
*
* Revision 1.14 2001/09/17 10:01:08 sable
* Added model AGFA 1236U
*
* Revision 1.13 2001/09/09 18:06:32 oliverschwartz
* add changes from Acer (new models; automatic firmware upload for USB scanners); fix distorted colour scans after greyscale scans (call set_window only in sane_start); code cleanup
*
* Revision 1.12 2001/04/10 13:00:31 sable
* Moving sanei_usb_* to snapscani_usb*
*
* Revision 1.11 2001/04/10 11:04:31 sable
* Adding support for snapscan e40 an e50 thanks to Giuseppe Tanzilli
*
* Revision 1.10 2001/03/17 22:53:21 sable
* Applying Mikael Magnusson patch concerning Gamma correction
* Support for 1212U_2
*
* Revision 1.9 2000/11/10 01:01:59 sable
* USB (kind of) autodetection
*
* Revision 1.8 2000/11/01 01:26:43 sable
* Support for 1212U
*
* Revision 1.7 2000/10/30 22:32:20 sable
* Support for vuego310s vuego610s and 1236s
*
* Revision 1.6 2000/10/29 22:44:55 sable
* Bug correction for 1236s
*
* Revision 1.5 2000/10/28 14:16:10 sable
* Bug correction for SnapScan310
*
* Revision 1.4 2000/10/28 14:06:35 sable
* Add support for Acer300f
*
* Revision 1.3 2000/10/15 19:52:06 cbagwell
* Changed USB support to a 1 line modification instead of multi-file
* changes.
*
* Revision 1.2 2000/10/13 03:50:27 cbagwell
* Updating to source from SANE 1.0.3. Calling this version 1.1
*
* */