kopia lustrzana https://gitlab.com/sane-project/backends
943 wiersze
29 KiB
C
943 wiersze
29 KiB
C
/* sane - Scanner Access Now Easy.
|
|
Artec AS6E backend.
|
|
Copyright (C) 2000 Eugene S. Weiss
|
|
This file is part of the SANE package.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
MA 02111-1307, USA.
|
|
|
|
As a special exception, the authors of SANE give permission for
|
|
additional uses of the libraries contained in this release of SANE.
|
|
|
|
The exception is that, if you link a SANE library with other files
|
|
to produce an executable, this does not by itself cause the
|
|
resulting executable to be covered by the GNU General Public
|
|
License. Your use of that executable is in no way restricted on
|
|
account of linking the SANE library code into it.
|
|
|
|
This exception does not, however, invalidate any other reasons why
|
|
the executable file might be covered by the GNU General Public
|
|
License.
|
|
|
|
If you submit changes to SANE to the maintainers to be included in
|
|
a subsequent release, you agree by submitting the changes that
|
|
those changes may be distributed with this exception intact.
|
|
|
|
If you write modifications of your own for SANE, it is your choice
|
|
whether to permit this exception to apply to your modifications.
|
|
If you do not wish that, delete this exception notice.
|
|
|
|
This file implements a backend for the Artec AS6E by making a bridge
|
|
to the as6edriver program. The as6edriver program can be found at
|
|
http://as6edriver.sourceforge.net . */
|
|
|
|
|
|
|
|
|
|
#include "../include/sane/config.h"
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "../include/sane/sane.h"
|
|
#include "../include/sane/saneopts.h"
|
|
|
|
#define BACKENDNAME as6e
|
|
#include "../include/sane/sanei_backend.h"
|
|
#include "../include/sane/sanei_config.h"
|
|
|
|
#include "as6e.h"
|
|
|
|
static int num_devices;
|
|
static AS6E_Device *first_dev;
|
|
static AS6E_Scan *first_handle;
|
|
static const SANE_Device **devlist = 0;
|
|
|
|
static SANE_Status attach (const char *devname, AS6E_Device ** devp);
|
|
/* static SANE_Status attach_one (const char *dev); */
|
|
|
|
static const SANE_String_Const mode_list[] = {
|
|
SANE_VALUE_SCAN_MODE_LINEART,
|
|
SANE_VALUE_SCAN_MODE_GRAY,
|
|
SANE_VALUE_SCAN_MODE_COLOR,
|
|
0
|
|
};
|
|
|
|
static const SANE_Word resolution_list[] = {
|
|
4, 300, 200, 100, 50
|
|
};
|
|
|
|
static const SANE_Range x_range = {
|
|
SANE_FIX (0),
|
|
SANE_FIX (215.91),
|
|
SANE_FIX (0)
|
|
};
|
|
|
|
static const SANE_Range y_range = {
|
|
SANE_FIX (0),
|
|
SANE_FIX (297.19),
|
|
SANE_FIX (0)
|
|
};
|
|
|
|
|
|
static const SANE_Range brightness_range = {
|
|
-100,
|
|
100,
|
|
1
|
|
};
|
|
|
|
static const SANE_Range contrast_range = {
|
|
-100,
|
|
100,
|
|
1
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static SANE_Int
|
|
as6e_unit_convert (SANE_Fixed value)
|
|
{
|
|
|
|
double precise;
|
|
SANE_Int return_value;
|
|
|
|
precise = SANE_UNFIX (value);
|
|
precise = (precise * 300) / MM_PER_INCH;
|
|
return_value = precise;
|
|
return return_value;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
SANE_Status
|
|
sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
|
|
SANE_Int * len)
|
|
{
|
|
AS6E_Scan *s = handle;
|
|
SANE_Word buffer_offset = 0;
|
|
int written = 0, bytes_read = 0, maxbytes;
|
|
SANE_Word bytecounter, linebufcounter, ctlbytes;
|
|
SANE_Byte *linebuffer;
|
|
|
|
DBG (3, "reading %d bytes, %d bytes in carryover buffer\n", max_len,
|
|
s->scan_buffer_count);
|
|
|
|
if ((unsigned int) s->image_counter >= s->bytes_to_read)
|
|
{
|
|
*len = 0;
|
|
if (s->scanning)
|
|
{
|
|
read (s->as6e_params.ctlinpipe, &written, sizeof (written));
|
|
if (written != -1)
|
|
DBG (3, "pipe error\n");
|
|
DBG (3, "trying to read -1 ...written = %d\n", written);
|
|
}
|
|
s->scanning = SANE_FALSE;
|
|
DBG (1, "image data complete, sending EOF...\n");
|
|
return SANE_STATUS_EOF;
|
|
} /*image complete */
|
|
|
|
linebuffer = s->line_buffer;
|
|
if (s->scan_buffer_count > 0)
|
|
{ /*there are leftover bytes from the last call */
|
|
if (s->scan_buffer_count <= max_len)
|
|
{
|
|
for (*len = 0; *len < s->scan_buffer_count; (*len)++)
|
|
{
|
|
buf[*len] = s->scan_buffer[*len];
|
|
buffer_offset++;
|
|
}
|
|
s->scan_buffer_count = 0;
|
|
if (s->scan_buffer_count == max_len)
|
|
{
|
|
s->scan_buffer_count = 0;
|
|
s->image_counter += max_len;
|
|
DBG (3, "returning %d bytes from the carryover buffer\n", *len);
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (*len = 0; *len < max_len; (*len)++)
|
|
buf[*len] = s->scan_buffer[*len];
|
|
|
|
for (bytecounter = max_len;
|
|
bytecounter < s->scan_buffer_count; bytecounter++)
|
|
s->scan_buffer[bytecounter - max_len]
|
|
= s->scan_buffer[bytecounter];
|
|
|
|
s->scan_buffer_count -= max_len;
|
|
s->image_counter += max_len;
|
|
DBG (3, "returning %d bytes from the carryover buffer\n", *len);
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*len = 0; /*no bytes in the buffer */
|
|
if (!s->scanning)
|
|
{
|
|
DBG (1, "scan over returning %d\n", *len);
|
|
if (s->scan_buffer_count)
|
|
return SANE_STATUS_GOOD;
|
|
else
|
|
return SANE_STATUS_EOF;
|
|
}
|
|
}
|
|
while (*len < max_len)
|
|
{
|
|
DBG (3, "trying to read number of bytes...\n");
|
|
ctlbytes = read (s->as6e_params.ctlinpipe, &written, sizeof (written));
|
|
DBG (3, "bytes written = %d, ctlbytes =%d\n", written, ctlbytes);
|
|
fflush (stdout);
|
|
if ((s->cancelled) && (written == 0))
|
|
{ /*first clear -1 from pipe */
|
|
DBG (1, "sending SANE_STATUS_CANCELLED\n");
|
|
read (s->as6e_params.ctlinpipe, &written, sizeof (written));
|
|
s->scanning = SANE_FALSE;
|
|
return SANE_STATUS_CANCELLED;
|
|
}
|
|
if (written == -1)
|
|
{
|
|
DBG (1, "-1READ Scanner through. returning %d bytes\n", *len);
|
|
s->image_counter += *len;
|
|
s->scanning = SANE_FALSE;
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
linebufcounter = 0;
|
|
DBG (3,
|
|
"linebufctr reset, len =%d written =%d bytes_read =%d, max = %d\n",
|
|
*len, written, bytes_read, max_len);
|
|
maxbytes = written;
|
|
while (linebufcounter < written)
|
|
{
|
|
DBG (4, "trying to read data pipe\n");
|
|
bytes_read =
|
|
read (s->as6e_params.datapipe, linebuffer + linebufcounter,
|
|
maxbytes);
|
|
linebufcounter += bytes_read;
|
|
maxbytes -= bytes_read;
|
|
DBG (3, "bytes_read = %d linebufcounter = %d\n", bytes_read,
|
|
linebufcounter);
|
|
}
|
|
DBG (3, "written =%d max_len =%d len =%d\n", written, max_len, *len);
|
|
if (written <= (max_len - *len))
|
|
{
|
|
for (bytecounter = 0; bytecounter < written; bytecounter++)
|
|
{
|
|
buf[bytecounter + buffer_offset] = linebuffer[bytecounter];
|
|
(*len)++;
|
|
}
|
|
buffer_offset += written;
|
|
DBG (3, "buffer offset = %d\n", buffer_offset);
|
|
}
|
|
else if (max_len > *len)
|
|
{ /*there's still room to send data */
|
|
for (bytecounter = 0; bytecounter < (max_len - *len); bytecounter++)
|
|
buf[bytecounter + buffer_offset] = linebuffer[bytecounter];
|
|
DBG (3, "topping off buffer\n");
|
|
for (bytecounter = (max_len - *len); bytecounter < written;
|
|
bytecounter++)
|
|
{
|
|
|
|
s->scan_buffer[s->scan_buffer_count + bytecounter -
|
|
(max_len - *len)] = linebuffer[bytecounter];
|
|
}
|
|
s->scan_buffer_count += (written - (max_len - *len));
|
|
*len = max_len;
|
|
}
|
|
else
|
|
{ /*everything goes into the carryover buffer */
|
|
for (bytecounter = 0; bytecounter < written; bytecounter++)
|
|
s->scan_buffer[s->scan_buffer_count + bytecounter]
|
|
= linebuffer[bytecounter];
|
|
s->scan_buffer_count += written;
|
|
}
|
|
} /*while there's space in the buffer */
|
|
s->image_counter += *len;
|
|
DBG (3, "image ctr = %d bytes_to_read = %lu returning %d\n",
|
|
s->image_counter, (u_long) s->bytes_to_read, *len);
|
|
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void
|
|
sane_cancel (SANE_Handle h)
|
|
{
|
|
AS6E_Scan *s = h;
|
|
SANE_Word test;
|
|
DBG (2, "trying to cancel...\n");
|
|
if (s->scanning)
|
|
{
|
|
test = kill (s->child_pid, SIGUSR1);
|
|
if (test == 0)
|
|
s->cancelled = SANE_TRUE;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
SANE_Status
|
|
sane_start (SANE_Handle handle)
|
|
{
|
|
AS6E_Scan *s = handle;
|
|
SANE_Status status;
|
|
int repeat = 1;
|
|
SANE_Word numbytes;
|
|
int scan_params[8];
|
|
/* First make sure we have a current parameter set. Some of the
|
|
* parameters will be overwritten below, but that's OK. */
|
|
DBG (2, "sane_start\n");
|
|
status = sane_get_parameters (s, 0);
|
|
if (status != SANE_STATUS_GOOD)
|
|
return status;
|
|
DBG (1, "Got params again...\n");
|
|
numbytes = write (s->as6e_params.ctloutpipe, &repeat, sizeof (repeat));
|
|
if (numbytes != sizeof (repeat))
|
|
return (SANE_STATUS_IO_ERROR);
|
|
DBG (1, "sending start_scan signal\n");
|
|
scan_params[0] = s->as6e_params.resolution;
|
|
if (strcmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0)
|
|
scan_params[1] = 0;
|
|
else if (strcmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY) == 0)
|
|
scan_params[1] = 1;
|
|
else if (strcmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART) == 0)
|
|
scan_params[1] = 2;
|
|
else
|
|
return (SANE_STATUS_JAMMED); /*this should never happen */
|
|
scan_params[2] = s->as6e_params.startpos;
|
|
scan_params[3] = s->as6e_params.stoppos;
|
|
scan_params[4] = s->as6e_params.startline;
|
|
scan_params[5] = s->as6e_params.stopline;
|
|
scan_params[6] = s->value[OPT_BRIGHTNESS].w;
|
|
scan_params[7] = s->value[OPT_CONTRAST].w;
|
|
DBG (1, "scan params = %d %d %d %d %d %d %d %d\n", scan_params[0],
|
|
scan_params[1], scan_params[2], scan_params[3],
|
|
scan_params[4], scan_params[5], scan_params[6], scan_params[7]);
|
|
numbytes =
|
|
write (s->as6e_params.ctloutpipe, scan_params, sizeof (scan_params));
|
|
if (numbytes != sizeof (scan_params))
|
|
return (SANE_STATUS_IO_ERROR);
|
|
s->scanning = SANE_TRUE;
|
|
s->scan_buffer_count = 0;
|
|
s->image_counter = 0;
|
|
s->cancelled = 0;
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
SANE_Status
|
|
sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
|
|
{
|
|
AS6E_Scan *s = handle;
|
|
SANE_String mode;
|
|
SANE_Word divisor = 1;
|
|
DBG (2, "sane_get_parameters\n");
|
|
if (!s->scanning)
|
|
{
|
|
memset (&s->sane_params, 0, sizeof (s->sane_params));
|
|
s->as6e_params.resolution = s->value[OPT_RESOLUTION].w;
|
|
s->as6e_params.startpos = as6e_unit_convert (s->value[OPT_TL_X].w);
|
|
s->as6e_params.stoppos = as6e_unit_convert (s->value[OPT_BR_X].w);
|
|
s->as6e_params.startline = as6e_unit_convert (s->value[OPT_TL_Y].w);
|
|
s->as6e_params.stopline = as6e_unit_convert (s->value[OPT_BR_Y].w);
|
|
if ((s->as6e_params.resolution == 200)
|
|
|| (s->as6e_params.resolution == 100))
|
|
divisor = 3;
|
|
else if (s->as6e_params.resolution == 50)
|
|
divisor = 6; /*get legal values for 200 dpi */
|
|
s->as6e_params.startpos = (s->as6e_params.startpos / divisor) * divisor;
|
|
s->as6e_params.stoppos = (s->as6e_params.stoppos / divisor) * divisor;
|
|
s->as6e_params.startline =
|
|
(s->as6e_params.startline / divisor) * divisor;
|
|
s->as6e_params.stopline = (s->as6e_params.stopline / divisor) * divisor;
|
|
s->sane_params.pixels_per_line =
|
|
(s->as6e_params.stoppos -
|
|
s->as6e_params.startpos) * s->as6e_params.resolution / 300;
|
|
s->sane_params.lines =
|
|
(s->as6e_params.stopline -
|
|
s->as6e_params.startline) * s->as6e_params.resolution / 300;
|
|
mode = s->value[OPT_MODE].s;
|
|
/* if ((strcmp (s->mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) ||
|
|
(strcmp (s->mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0))
|
|
{
|
|
s->sane_params.format = SANE_FRAME_GRAY;
|
|
s->sane_params.bytes_per_line = (s->sane_params.pixels_per_line + 7) / 8;
|
|
s->sane_params.depth = 1;
|
|
} */
|
|
/*else*/ if ((strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
|
|
|| (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0))
|
|
{
|
|
s->sane_params.format = SANE_FRAME_GRAY;
|
|
s->sane_params.bytes_per_line = s->sane_params.pixels_per_line;
|
|
s->sane_params.depth = 8;
|
|
} /*grey frame */
|
|
else
|
|
{
|
|
s->sane_params.format = SANE_FRAME_RGB;
|
|
s->sane_params.bytes_per_line = 3 * s->sane_params.pixels_per_line;
|
|
s->sane_params.depth = 8;
|
|
} /*color frame */
|
|
s->bytes_to_read = s->sane_params.lines * s->sane_params.bytes_per_line;
|
|
s->sane_params.last_frame = SANE_TRUE;
|
|
} /*!scanning */
|
|
|
|
if (params)
|
|
*params = s->sane_params;
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
SANE_Status
|
|
sane_control_option (SANE_Handle handle, SANE_Int option,
|
|
SANE_Action action, void *val, SANE_Int * info)
|
|
{
|
|
AS6E_Scan *s = handle;
|
|
SANE_Status status = 0;
|
|
SANE_Word cap;
|
|
DBG (2, "sane_control_option\n");
|
|
if (info)
|
|
*info = 0;
|
|
if (s->scanning)
|
|
return SANE_STATUS_DEVICE_BUSY;
|
|
if (option >= NUM_OPTIONS)
|
|
return SANE_STATUS_INVAL;
|
|
cap = s->options_list[option].cap;
|
|
if (!SANE_OPTION_IS_ACTIVE (cap))
|
|
return SANE_STATUS_INVAL;
|
|
if (action == SANE_ACTION_GET_VALUE)
|
|
{
|
|
DBG (1, "sane_control_option %d, get value\n", option);
|
|
switch (option)
|
|
{
|
|
/* word options: */
|
|
case OPT_RESOLUTION:
|
|
case OPT_TL_X:
|
|
case OPT_TL_Y:
|
|
case OPT_BR_X:
|
|
case OPT_BR_Y:
|
|
case OPT_NUM_OPTS:
|
|
case OPT_CONTRAST:
|
|
case OPT_BRIGHTNESS:
|
|
*(SANE_Word *) val = s->value[option].w;
|
|
return (SANE_STATUS_GOOD);
|
|
/* string options: */
|
|
case OPT_MODE:
|
|
strcpy (val, s->value[option].s);
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
}
|
|
else if (action == SANE_ACTION_SET_VALUE)
|
|
{
|
|
DBG (1, "sane_control_option %d, set value\n", option);
|
|
if (!SANE_OPTION_IS_SETTABLE (cap))
|
|
return (SANE_STATUS_INVAL);
|
|
/* status = sanei_constrain_value (s->options_list[option], val, info);*/
|
|
if (status != SANE_STATUS_GOOD)
|
|
return (status);
|
|
switch (option)
|
|
{
|
|
/* (mostly) side-effect-free word options: */
|
|
case OPT_RESOLUTION:
|
|
case OPT_BR_X:
|
|
case OPT_BR_Y:
|
|
case OPT_TL_X:
|
|
case OPT_TL_Y:
|
|
if (info && s->value[option].w != *(SANE_Word *) val)
|
|
*info |= SANE_INFO_RELOAD_PARAMS;
|
|
/* fall through */
|
|
case OPT_NUM_OPTS:
|
|
case OPT_CONTRAST:
|
|
case OPT_BRIGHTNESS:
|
|
s->value[option].w = *(SANE_Word *) val;
|
|
DBG (1, "set brightness to\n");
|
|
return (SANE_STATUS_GOOD);
|
|
case OPT_MODE:
|
|
if (s->value[option].s)
|
|
free (s->value[option].s);
|
|
s->value[option].s = strdup (val);
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
}
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
const SANE_Option_Descriptor *
|
|
sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
|
|
{
|
|
AS6E_Scan *s = handle;
|
|
DBG (2, "sane_get_option_descriptor\n");
|
|
if ((unsigned) option >= NUM_OPTIONS)
|
|
return (0);
|
|
return (&s->options_list[option]);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
sane_close (SANE_Handle handle)
|
|
{
|
|
AS6E_Scan *prev, *s;
|
|
SANE_Word repeat = 0;
|
|
DBG (2, "sane_close\n");
|
|
/* remove handle from list of open handles: */
|
|
prev = 0;
|
|
for (s = first_handle; s; s = s->next)
|
|
{
|
|
if (s == handle)
|
|
break;
|
|
prev = s;
|
|
}
|
|
if (!s)
|
|
{
|
|
DBG (1, "close: invalid handle %p\n", handle);
|
|
return; /* oops, not a handle we know about */
|
|
}
|
|
|
|
if (s->scanning)
|
|
sane_cancel (handle);
|
|
write (s->as6e_params.ctloutpipe, &repeat, sizeof (repeat));
|
|
close (s->as6e_params.ctloutpipe);
|
|
free (s->scan_buffer);
|
|
free (s->line_buffer);
|
|
if (prev)
|
|
prev->next = s->next;
|
|
else
|
|
first_handle = s;
|
|
free (handle);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void
|
|
sane_exit (void)
|
|
{
|
|
AS6E_Device *next;
|
|
DBG (2, "sane_exit\n");
|
|
while (first_dev != NULL)
|
|
{
|
|
next = first_dev->next;
|
|
free (first_dev);
|
|
first_dev = next;
|
|
}
|
|
if (devlist)
|
|
free (devlist);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static SANE_Status
|
|
as6e_open (AS6E_Scan * s)
|
|
{
|
|
|
|
int data_processed, exec_result, as6e_status;
|
|
int ctloutpipe[2], ctlinpipe[2], datapipe[2];
|
|
char inpipe_desc[32], outpipe_desc[32], datapipe_desc[32];
|
|
pid_t fork_result;
|
|
DBG (1, "as6e_open\n");
|
|
memset (inpipe_desc, '\0', sizeof (inpipe_desc));
|
|
memset (outpipe_desc, '\0', sizeof (outpipe_desc));
|
|
memset (datapipe_desc, '\0', sizeof (datapipe_desc));
|
|
if ((pipe (ctloutpipe) == 0) && (pipe (ctlinpipe) == 0)
|
|
&& (pipe (datapipe) == 0))
|
|
{
|
|
fork_result = fork ();
|
|
if (fork_result == (pid_t) - 1)
|
|
{
|
|
DBG (1, "Fork failure");
|
|
return (SANE_STATUS_IO_ERROR);
|
|
}
|
|
|
|
if (fork_result == 0)
|
|
{ /*in child */
|
|
sprintf (inpipe_desc, "%d", ctlinpipe[WRITEPIPE]);
|
|
sprintf (outpipe_desc, "%d", ctloutpipe[READPIPE]);
|
|
sprintf (datapipe_desc, "%d", datapipe[WRITEPIPE]);
|
|
exec_result =
|
|
execlp ("as6edriver", "as6edriver", "-s", inpipe_desc,
|
|
outpipe_desc, datapipe_desc, (char *) 0);
|
|
DBG (1, "The SANE backend was unable to start \"as6edriver\".\n");
|
|
DBG (1, "This must be installed in a driectory in your PATH.\n");
|
|
DBG (1, "To aquire the as6edriver program,\n");
|
|
DBG (1, "go to http://as6edriver.sourceforge.net.\n");
|
|
write (ctlinpipe[WRITEPIPE], &exec_result, sizeof (exec_result));
|
|
exit (-1);
|
|
}
|
|
else
|
|
{ /*parent process */
|
|
data_processed =
|
|
read (ctlinpipe[READPIPE], &as6e_status, sizeof (as6e_status));
|
|
DBG (1, "%d - read %d status = %d\n", getpid (), data_processed,
|
|
as6e_status);
|
|
if (as6e_status == -2)
|
|
{
|
|
DBG (1, "Port access denied.\n");
|
|
return (SANE_STATUS_IO_ERROR);
|
|
}
|
|
if (as6e_status == -1)
|
|
{
|
|
DBG (1, "Could not contact scanner.\n");
|
|
return (SANE_STATUS_IO_ERROR);
|
|
}
|
|
|
|
if (as6e_status == 1)
|
|
DBG (1, "Using nibble mode.\n");
|
|
if (as6e_status == 2)
|
|
DBG (1, "Using byte mode.\n");
|
|
if (as6e_status == 3)
|
|
DBG (1, "Using EPP mode.\n");
|
|
s->as6e_params.ctlinpipe = ctlinpipe[READPIPE];
|
|
s->as6e_params.ctloutpipe = ctloutpipe[WRITEPIPE];
|
|
s->as6e_params.datapipe = datapipe[READPIPE];
|
|
s->child_pid = fork_result;
|
|
return (SANE_STATUS_GOOD);
|
|
} /*else */
|
|
}
|
|
else
|
|
return (SANE_STATUS_IO_ERROR);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
SANE_Status
|
|
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
|
|
{
|
|
char dev_name[PATH_MAX];
|
|
size_t len;
|
|
FILE *fp = NULL;
|
|
|
|
DBG_INIT ();
|
|
DBG (2, "sane_init (authorize %s null)\n", (authorize) ? "!=" : "==");
|
|
if (version_code)
|
|
*version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, 0);
|
|
/* fp = sanei_config_open (AS6E_CONFIG_FILE);*/
|
|
if (!fp)
|
|
{
|
|
return (attach ("as6edriver", 0));
|
|
}
|
|
|
|
while (fgets (dev_name, sizeof (dev_name), fp))
|
|
{
|
|
if (dev_name[0] == '#') /* ignore line comments */
|
|
continue;
|
|
len = strlen (dev_name);
|
|
if (dev_name[len - 1] == '\n')
|
|
dev_name[--len] = '\0';
|
|
if (!len)
|
|
continue; /* ignore empty lines */
|
|
/* sanei_config_attach_matching_devices (dev_name, attach_one);*/
|
|
}
|
|
fclose (fp);
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/*
|
|
static SANE_Status
|
|
attach_one (const char *dev)
|
|
{
|
|
DBG (2, "attach_one\n");
|
|
attach (dev, 0);
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
SANE_Status
|
|
sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
|
|
{
|
|
static const SANE_Device **devlist = 0;
|
|
AS6E_Device *dev;
|
|
int i;
|
|
DBG (3, "sane_get_devices (local_only = %d)\n", local_only);
|
|
if (devlist)
|
|
free (devlist);
|
|
devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
|
|
if (!devlist)
|
|
return SANE_STATUS_NO_MEM;
|
|
i = 0;
|
|
for (dev = first_dev; i < num_devices; dev = dev->next)
|
|
devlist[i++] = &dev->sane;
|
|
devlist[i++] = 0;
|
|
*device_list = devlist;
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
static size_t
|
|
max_string_size (const SANE_String_Const strings[])
|
|
{
|
|
size_t size, max_size = 0;
|
|
int i;
|
|
for (i = 0; strings[i]; ++i)
|
|
{
|
|
size = strlen (strings[i]) + 1;
|
|
if (size > max_size)
|
|
max_size = size;
|
|
}
|
|
|
|
return (max_size);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
static void
|
|
initialize_options_list (AS6E_Scan * s)
|
|
{
|
|
|
|
SANE_Int option;
|
|
DBG (2, "initialize_options_list\n");
|
|
for (option = 0; option < NUM_OPTIONS; ++option)
|
|
{
|
|
s->options_list[option].size = sizeof (SANE_Word);
|
|
s->options_list[option].cap =
|
|
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
|
|
}
|
|
|
|
s->options_list[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
|
|
s->options_list[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
|
|
s->options_list[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
|
|
s->options_list[OPT_NUM_OPTS].type = SANE_TYPE_INT;
|
|
s->options_list[OPT_NUM_OPTS].unit = SANE_UNIT_NONE;
|
|
s->options_list[OPT_NUM_OPTS].size = sizeof (SANE_Word);
|
|
s->options_list[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
|
|
s->options_list[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE;
|
|
s->value[OPT_NUM_OPTS].w = NUM_OPTIONS;
|
|
s->options_list[OPT_MODE].name = SANE_NAME_SCAN_MODE;
|
|
s->options_list[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
|
|
s->options_list[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
|
|
s->options_list[OPT_MODE].type = SANE_TYPE_STRING;
|
|
s->options_list[OPT_MODE].size = max_string_size (mode_list);
|
|
s->options_list[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
|
s->options_list[OPT_MODE].constraint.string_list = mode_list;
|
|
s->value[OPT_MODE].s = strdup (mode_list[2]);
|
|
s->options_list[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
|
|
s->options_list[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
|
|
s->options_list[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
|
|
s->options_list[OPT_RESOLUTION].type = SANE_TYPE_INT;
|
|
s->options_list[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
|
|
s->options_list[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
|
|
s->options_list[OPT_RESOLUTION].constraint.word_list = resolution_list;
|
|
s->value[OPT_RESOLUTION].w = 200;
|
|
s->options_list[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
|
|
s->options_list[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
|
|
s->options_list[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
|
|
s->options_list[OPT_TL_X].type = SANE_TYPE_FIXED;
|
|
s->options_list[OPT_TL_X].unit = SANE_UNIT_MM;
|
|
s->options_list[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->options_list[OPT_TL_X].constraint.range = &x_range;
|
|
s->value[OPT_TL_X].w = s->options_list[OPT_TL_X].constraint.range->min;
|
|
s->options_list[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
|
|
s->options_list[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
|
|
s->options_list[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
|
|
s->options_list[OPT_TL_Y].type = SANE_TYPE_FIXED;
|
|
s->options_list[OPT_TL_Y].unit = SANE_UNIT_MM;
|
|
s->options_list[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->options_list[OPT_TL_Y].constraint.range = &y_range;
|
|
s->value[OPT_TL_Y].w = s->options_list[OPT_TL_Y].constraint.range->min;
|
|
s->options_list[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
|
|
s->options_list[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
|
|
s->options_list[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
|
|
s->options_list[OPT_BR_X].type = SANE_TYPE_FIXED;
|
|
s->options_list[OPT_BR_X].unit = SANE_UNIT_MM;
|
|
s->options_list[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->options_list[OPT_BR_X].constraint.range = &x_range;
|
|
s->value[OPT_BR_X].w = s->options_list[OPT_BR_X].constraint.range->max;
|
|
s->options_list[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
|
|
s->options_list[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
|
|
s->options_list[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
|
|
s->options_list[OPT_BR_Y].type = SANE_TYPE_FIXED;
|
|
s->options_list[OPT_BR_Y].unit = SANE_UNIT_MM;
|
|
s->options_list[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->options_list[OPT_BR_Y].constraint.range = &y_range;
|
|
s->value[OPT_BR_Y].w = s->options_list[OPT_BR_Y].constraint.range->max;
|
|
s->options_list[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
|
|
s->options_list[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
|
|
s->options_list[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
|
|
s->options_list[OPT_CONTRAST].type = SANE_TYPE_INT;
|
|
s->options_list[OPT_CONTRAST].unit = SANE_UNIT_NONE;
|
|
s->options_list[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->options_list[OPT_CONTRAST].constraint.range = &brightness_range;
|
|
s->value[OPT_BRIGHTNESS].w = 10;
|
|
s->options_list[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
|
|
s->options_list[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
|
|
s->options_list[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
|
|
s->options_list[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
|
|
s->options_list[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
|
|
s->options_list[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
|
|
s->options_list[OPT_BRIGHTNESS].constraint.range = &contrast_range;
|
|
s->value[OPT_CONTRAST].w = -32;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int
|
|
check_for_driver (const char *devname)
|
|
{
|
|
#define NAMESIZE 128
|
|
struct stat statbuf;
|
|
mode_t modes;
|
|
char *path;
|
|
char fullname[NAMESIZE];
|
|
char dir[NAMESIZE];
|
|
int count = 0, offset = 0;
|
|
|
|
path = getenv ("PATH");
|
|
if (!path)
|
|
return 0;
|
|
while (path[count] != '\0')
|
|
{
|
|
memset (fullname, '\0', sizeof (fullname));
|
|
memset (dir, '\0', sizeof (dir));
|
|
while ((path[count] != ':') && (path[count] != '\0'))
|
|
{
|
|
dir[count - offset] = path[count];
|
|
count++;
|
|
}
|
|
/* use sizeof(fullname)-1 to make sure there is at least one padded null byte */
|
|
strncpy (fullname, dir, sizeof(fullname)-1);
|
|
/* take into account that fullname already contains non-null bytes */
|
|
strncat (fullname, "/", sizeof(fullname)-strlen(fullname)-1);
|
|
strncat (fullname, devname, sizeof(fullname)-strlen(fullname)-1);
|
|
if (!stat (fullname, &statbuf))
|
|
{
|
|
modes = statbuf.st_mode;
|
|
if (S_ISREG (modes))
|
|
return (1); /* found as6edriver */
|
|
}
|
|
if (path[count] == '\0')
|
|
return (0); /* end of path --no driver found */
|
|
count++;
|
|
offset = count;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static SANE_Status
|
|
attach (const char *devname, AS6E_Device ** devp)
|
|
{
|
|
|
|
AS6E_Device *dev;
|
|
|
|
/* SANE_Status status; */
|
|
DBG (2, "attach\n");
|
|
for (dev = first_dev; dev; dev = dev->next)
|
|
{
|
|
if (strcmp (dev->sane.name, devname) == 0)
|
|
{
|
|
if (devp)
|
|
*devp = dev;
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
}
|
|
dev = malloc (sizeof (*dev));
|
|
if (!dev)
|
|
return (SANE_STATUS_NO_MEM);
|
|
memset (dev, 0, sizeof (*dev));
|
|
dev->sane.name = strdup (devname);
|
|
if (!check_for_driver (devname))
|
|
{
|
|
free (dev);
|
|
return (SANE_STATUS_INVAL);
|
|
}
|
|
|
|
dev->sane.model = "AS6E";
|
|
dev->sane.vendor = "Artec";
|
|
dev->sane.type = "flatbed scanner";
|
|
++num_devices;
|
|
dev->next = first_dev;
|
|
first_dev = dev;
|
|
if (devp)
|
|
*devp = dev;
|
|
return (SANE_STATUS_GOOD);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
SANE_Status
|
|
sane_open (SANE_String_Const devicename, SANE_Handle * handle)
|
|
{
|
|
SANE_Status status;
|
|
AS6E_Device *dev;
|
|
AS6E_Scan *s;
|
|
DBG (2, "sane_open\n");
|
|
if (devicename[0])
|
|
{
|
|
for (dev = first_dev; dev; dev = dev->next)
|
|
if (strcmp (dev->sane.name, devicename) == 0)
|
|
break;
|
|
if (!dev)
|
|
{
|
|
status = attach (devicename, &dev);
|
|
if (status != SANE_STATUS_GOOD)
|
|
return (status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* empty devicname -> use first device */
|
|
dev = first_dev;
|
|
}
|
|
if (!dev)
|
|
return SANE_STATUS_INVAL;
|
|
s = malloc (sizeof (*s));
|
|
if (!s)
|
|
return SANE_STATUS_NO_MEM;
|
|
memset (s, 0, sizeof (*s));
|
|
s->scan_buffer = malloc (SCAN_BUF_SIZE);
|
|
if (!s->scan_buffer)
|
|
return SANE_STATUS_NO_MEM;
|
|
memset (s->scan_buffer, 0, SCAN_BUF_SIZE);
|
|
s->line_buffer = malloc (SCAN_BUF_SIZE);
|
|
if (!s->line_buffer)
|
|
return SANE_STATUS_NO_MEM;
|
|
memset (s->line_buffer, 0, SCAN_BUF_SIZE);
|
|
status = as6e_open (s);
|
|
if (status != SANE_STATUS_GOOD)
|
|
return status;
|
|
initialize_options_list (s);
|
|
s->scanning = 0;
|
|
/* insert newly opened handle into list of open handles: */
|
|
s->next = first_handle;
|
|
first_handle = s;
|
|
*handle = s;
|
|
return (status);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
SANE_Status
|
|
sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
|
|
{
|
|
DBG (2, "sane_set_io_mode( %p, %d )\n", handle, non_blocking);
|
|
return (SANE_STATUS_UNSUPPORTED);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
SANE_Status
|
|
sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
|
|
{
|
|
DBG (2, "sane_get_select_fd( %p, %p )\n",(void *) handle, (void *) fd);
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
}
|