sane-project-backends/backend/as6e.c

896 wiersze
27 KiB
C

/***************************************************************************
as6e.c - description
-------------------
begin : Mon Feb 21 20:27:05 EST 2000
copyright : (C) 2000 by Eugene Weiss
email : eweiss@sas.upenn.edu
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#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 "as6e.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"
static int num_devices;
static AS6E_Device *first_dev;
static AS6E_Scan *first_handle;
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[] = {
"Lineart", "Gray", "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, "\nreading %d bytes, %d bytes in carryover buffer", max_len,
s->scan_buffer_count);
if (s->image_counter >= s->bytes_to_read)
{
*len = 0;
if (s->scanning)
{
read (s->as6e_params.ctlinpipe, &written, sizeof (written));
if (written != -1)
printf ("\npipe error");
DBG (3, "\ntrying to read -1 ...written = %d", written);
}
s->scanning = SANE_FALSE;
DBG (1, "\nimage data complete, sending EOF...");
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, "\nreturning %d bytes from the carryover buffer", *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, "\nreturning %d bytes from the carryover buffer", *len);
return SANE_STATUS_GOOD;
}
}
else
{
*len = 0; /*no bytes in the buffer */
if (!s->scanning)
{
DBG (1, "\nscan over returning %d", *len);
if (s->scan_buffer_count)
return SANE_STATUS_GOOD;
else
return SANE_STATUS_EOF;
}
}
while (*len < max_len)
{
DBG (3, "\ntrying to read number of bytes...");
ctlbytes = read (s->as6e_params.ctlinpipe, &written, sizeof (written));
DBG (3, "\nbytes written = %d, ctlbytes =%d", written, ctlbytes);
fflush (stdout);
if ((s->cancelled) && (written == 0))
{ /*first clear -1 from pipe */
DBG (1, "\nsending SANE_STATUS_CANCELLED");
read (s->as6e_params.ctlinpipe, &written, sizeof (written));
s->scanning = SANE_FALSE;
return SANE_STATUS_CANCELLED;
}
if (written == -1)
{
DBG (1, "\n-1READ Scanner through. returning %d bytes", *len);
s->image_counter += *len;
s->scanning = SANE_FALSE;
return SANE_STATUS_GOOD;
}
linebufcounter = 0;
DBG (3,
"\nlinebufctr reset, len =%d written =%d bytes_read =%d, max = %d",
*len, written, bytes_read, max_len);
maxbytes = written;
while (linebufcounter < written)
{
DBG (4, "\ntrying to read data pipe");
bytes_read =
read (s->as6e_params.datapipe, linebuffer + linebufcounter,
maxbytes);
linebufcounter += bytes_read;
maxbytes -= bytes_read;
DBG (3, "\nbytes_read = %d linebufcounter = %d", bytes_read,
linebufcounter);}
DBG (3, "\nwritten =%d max_len =%d len =%d", 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, "\nbuffer offset = %d", 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, "\ntopping off buffer");
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, "\nimage ctr = %d bytes_to_read = %d returning %d",
s->image_counter, s->bytes_to_read, *len);
return SANE_STATUS_GOOD;
}
/*--------------------------------------------------------------------------*/
void
sane_cancel (SANE_Handle h)
{
AS6E_Scan *s = h;
SANE_Word test;
DBG (2, "\ntrying to cancel...");
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, "\nsane_start");
status = sane_get_parameters (s, 0);
if (status != SANE_STATUS_GOOD)
return status;
DBG (1, "\nGot params again...");
numbytes = write (s->as6e_params.ctloutpipe, &repeat, sizeof (repeat));
if (numbytes != sizeof (repeat))
return (SANE_STATUS_IO_ERROR);
DBG (1, "\nsending start_scan signal");
scan_params[0] = s->as6e_params.resolution;
if (strcmp (s->value[OPT_MODE].s, "Color") == 0)
scan_params[1] = 0;
else if (strcmp (s->value[OPT_MODE].s, "Gray") == 0)
scan_params[1] = 1;
else if (strcmp (s->value[OPT_MODE].s, "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, "\nscan params = %d %d %d %d %d %d %d %d", 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, "\nsane_get_parameters");
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, "Lineart") == 0) ||
(strcmp (s->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, "Gray") == 0)
|| (strcmp (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, "\nsane_control_option");
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, "\nset brightness to");
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, "\nsane_get_option_descriptor");
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, "\nsane_close");
/* 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, "\nsane_exit");
while (first_dev != NULL)
{
next = first_dev->next;
/* free((void *) first_dev->sane.name);*/
/* free((void *) first_dev->sane.model);*/
free (first_dev);
first_dev = next;
}
}
/*--------------------------------------------------------------------------*/
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, "\nas6e_open");
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)
{
fprintf (stderr, "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);
printf ("\nThe SANE backend was unable to start \"as6edriver\".");
printf ("\nThis must be installed in a driectory in your PATH.\n");
printf ("\nTo aquire the as6edriver program,");
printf ("\ngo to http://as6edriver.sourceforge.net.");
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)
{
printf ("\nPort access denied.");
return (SANE_STATUS_IO_ERROR);
}
if (as6e_status == -1)
{
printf ("\nCould not contact scanner.");
return (SANE_STATUS_IO_ERROR);
}
if (as6e_status == 1)
printf ("\nUsing nibble mode.");
if (as6e_status == 2)
printf ("\nUsing byte mode.");
if (as6e_status == 3)
printf ("\nUsing EPP mode.");
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, "\nsane_init");
if (version_code)
*version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 0);
/* fp = sanei_config_open (AS6E_CONFIG_FILE);*/
if (!fp)
{
/* attach ("as6edriver", 0);*/
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, "\nsane_get_devices");
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, "\ninitialize_options_list");
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");
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++;
}
strncpy (fullname, dir, NAMESIZE);
strncat (fullname, "/", NAMESIZE);
strncat (fullname, devname, NAMESIZE);
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, "\nattach");
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))
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, "\nsane_open");
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)
{
return SANE_STATUS_UNSUPPORTED;
}