diff --git a/AUTHORS b/AUTHORS index eaa5a4e5f..1b982e222 100644 --- a/AUTHORS +++ b/AUTHORS @@ -12,6 +12,7 @@ Backends: agfafocus: Karl Anders Øygard apple: Milon Firikis artec: Chris Pinkham (*) + as6e: Eugene S. Weiss (*) avision: Meino Christian Cramer, Rene Rebe(*) canon: Helmut Koeberle, Manuel Panea (*), and Markus Mertinat coolscan: Didier Carlier, Andreas Rick (*) @@ -80,6 +81,7 @@ David F. Skoll David Huggins-Daines David Mosberger Didier Carlier +Eugene S. Weiss FUKUDA Kazuya Juergen G. Schimmer Feico W. Dillema diff --git a/PROJECTS b/PROJECTS index 10631e0b8..3223ed997 100644 --- a/PROJECTS +++ b/PROJECTS @@ -1,4 +1,4 @@ -PROJECTS (2000-11-15) +PROJECTS (2000-11-19) Here is a list of projects that various people have expressed interest in. Before starting working on one of these projects, it may be a @@ -16,9 +16,6 @@ wip Work in progress. There is (more or less) working code. For details, Backends: --------- -Artec AS6E (wip) -http://as6edriver.sourceforge.net/ - Autobrightness/contrast for cameras etc. (planned?) David Mosberger diff --git a/README b/README index 0cc6a2012..2f906191f 100644 --- a/README +++ b/README @@ -105,6 +105,7 @@ below: AGFA SnapScan sane-snapscan(5) Apple sane-apple(5) Artec sane-artec(5) + Artec AS6E parport sane-as6e(5) Avision sane-avision(5) Canon sane-canon(5) Nikon Coolscan sane-coolscan(5) diff --git a/backend/Makefile.in b/backend/Makefile.in index f48b3de5d..44e45f438 100644 --- a/backend/Makefile.in +++ b/backend/Makefile.in @@ -51,10 +51,10 @@ COMPILE = $(CC) -c $(CFLAGS) $(DEFS) $(INCLUDES) $(CPPFLAGS) @SET_MAKE@ -PRELOADABLE_BACKENDS = abaton agfafocus apple artec avision canon coolscan \ - dc25 @DC210@ dmc epson hp m3096g microtek microtek2 mustek mustek_pp \ - @NET@ pie @PINT@ plustek pnm @QCAM@ ricoh s9036 sharp snapscan sp15c \ - st400 tamarack umax @V4L@ +PRELOADABLE_BACKENDS = abaton agfafocus apple artec as6e avision canon \ + coolscan dc25 @DC210@ dmc epson hp m3096g microtek microtek2 mustek \ + mustek_pp @NET@ pie @PINT@ plustek pnm @QCAM@ ricoh s9036 sharp \ + snapscan sp15c st400 tamarack umax @V4L@ ALL_BACKENDS = $(PRELOADABLE_BACKENDS) dll LIBS = $(addprefix libsane-,$(addsuffix .la,$(ALL_BACKENDS))) @@ -176,6 +176,8 @@ libsane-apple.la: ../sanei/sanei_scsi.lo libsane-artec.la: ../sanei/sanei_config2.lo libsane-artec.la: ../sanei/sanei_constrain_value.lo libsane-artec.la: ../sanei/sanei_scsi.lo +libsane-as6e.la: ../sanei/sanei_config2.lo +libsane-as6e.la: ../sanei/sanei_constrain_value.lo libsane-avision.la: ../sanei/sanei_config2.lo libsane-avision.la: ../sanei/sanei_constrain_value.lo libsane-avision.la: ../sanei/sanei_scsi.lo diff --git a/backend/as6e.c b/backend/as6e.c new file mode 100644 index 000000000..7f6b5ef05 --- /dev/null +++ b/backend/as6e.c @@ -0,0 +1,895 @@ + /*************************************************************************** + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/backend/as6e.desc b/backend/as6e.desc index c485c7e7e..ccfef266f 100644 --- a/backend/as6e.desc +++ b/backend/as6e.desc @@ -8,10 +8,10 @@ ; All other information is optional (but what good is the file without it?). ; -:backend "as6e" ; name of backend -:version "(0.4.0)" ; version of backend -:status :alpha ; :alpha, :beta, :stable, :new -;:manpage "sane-as6e" ; name of manpage (if it exists) +:backend "as6e" ; name of backend +:version "0.4.2" ; version of backend +:status :new ; :alpha, :beta, :stable, :new +:manpage "sane-as6e" ; name of manpage (if it exists) :url "http://as6edriver.sourceforge.net/" :devicetype :scanner @@ -21,7 +21,7 @@ :model "AS6E" :interface "Parport" -:comment "all modes working" +:comment "Requires the program 'as6edriver' to run." ; :comment and :url specifiers are optional after :mfg, :model, :desc, diff --git a/backend/as6e.h b/backend/as6e.h new file mode 100644 index 000000000..d97aa5a97 --- /dev/null +++ b/backend/as6e.h @@ -0,0 +1,98 @@ +/*************************************************************************** + as6e.h - description + ------------------- + begin : Mon Feb 21 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 +#include + + +typedef union +{ + SANE_Word w; /* word */ + SANE_Word *wa; /* word array */ + SANE_String s; /* string */ +} Option_Value; + +typedef enum +{ + OPT_NUM_OPTS = 0, + OPT_MODE, + OPT_RESOLUTION, + + OPT_TL_X, /* top-left x */ + OPT_TL_Y, /* top-left y */ + OPT_BR_X, /* bottom-right x */ + OPT_BR_Y, /* bottom-right y */ + + OPT_BRIGHTNESS, + OPT_CONTRAST, + + /* must come last */ + NUM_OPTIONS + } AS6E_Option; + +typedef struct +{ + int color; + int resolution; + int startpos; + int stoppos; + int startline; + int stopline; + int ctloutpipe; + int ctlinpipe; + int datapipe; +} AS6E_Params; + + +typedef struct AS6E_Device +{ + struct AS6E_Device *next; + SANE_Device sane; +} AS6E_Device; + + + +typedef struct AS6E_Scan +{ + struct AS6E_Scan *next; + SANE_Option_Descriptor options_list[NUM_OPTIONS]; + Option_Value value[NUM_OPTIONS]; + SANE_Bool scanning; + SANE_Bool cancelled; + SANE_Parameters sane_params; + AS6E_Params as6e_params; + pid_t child_pid; + size_t bytes_to_read; + SANE_Byte *scan_buffer; + SANE_Byte *line_buffer; + SANE_Word scan_buffer_count; + SANE_Word image_counter; +} AS6E_Scan; + + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +#define AS6E_CONFIG_FILE "as6e.conf" + +#define READPIPE 0 +#define WRITEPIPE 1 + +#define MM_PER_INCH 25.4 + +#define SCAN_BUF_SIZE 32768 diff --git a/backend/dll.conf b/backend/dll.conf index 71bcf4b59..3e3e38f17 100644 --- a/backend/dll.conf +++ b/backend/dll.conf @@ -5,6 +5,7 @@ agfafocus apple avision artec +as6e canon coolscan #dc25 diff --git a/doc/Makefile.in b/doc/Makefile.in index 2408bb4dc..49179cc54 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -31,13 +31,14 @@ LN_S = @LN_S@ @SET_MAKE@ SECT1 = saned.1 scanimage.1 xscanimage.1 xcam.1 -SECT5 = sane-abaton.5 sane-agfafocus.5 sane-apple.5 sane-dll.5 sane-dc25.5 \ - sane-dmc.5 sane-epson.5 sane-hp.5 sane-microtek.5 sane-microtek2.5 \ - sane-mustek.5 sane-net.5 sane-pie.5 sane-pint.5 sane-pnm.5 sane-umax.5 \ - sane-qcam.5 sane-scsi.5 sane-artec.5 sane-fujitsu.5 sane-sharp.5 \ - sane-s9036.5 sane-tamarack.5 sane-ricoh.5 sane-avision.5 \ - sane-plustek.5 sane-st400.5 sane-mustek_pp.5 sane-dc210.5 \ - sane-v4l.5 sane-snapscan.5 sane-canon.5 sane-coolscan.5 +SECT5 = sane-abaton.5 sane-agfafocus.5 sane-apple.5 sane-as6e.5 sane-dll.5 \ + sane-dc25.5 sane-dmc.5 sane-epson.5 sane-hp.5 sane-microtek.5 \ + sane-microtek2.5 sane-mustek.5 sane-net.5 sane-pie.5 sane-pint.5 \ + sane-pnm.5 sane-umax.5 sane-qcam.5 sane-scsi.5 sane-artec.5 \ + sane-fujitsu.5 sane-sharp.5 sane-s9036.5 sane-tamarack.5 \ + sane-ricoh.5 sane-avision.5 sane-plustek.5 sane-st400.5 \ + sane-mustek_pp.5 sane-dc210.5 sane-v4l.5 sane-snapscan.5 \ + sane-canon.5 sane-coolscan.5 MANPAGES = $(SECT1) $(SECT5) DOCS = sane.ps sane.dvi LATEX = TEXINPUTS=$(srcdir):$$TEXINPUTS latex diff --git a/doc/sane-as6e.man b/doc/sane-as6e.man new file mode 100644 index 000000000..deb6b4dcd --- /dev/null +++ b/doc/sane-as6e.man @@ -0,0 +1,33 @@ +.TH sane-as6e 5 " November 19, 2000" "SANE Artec AS6E Backend " + +.SH NAME +sane-as6e \-SANE backend for using the Artec AS6E parallel port interface scanner. + +.SH DESCRIPTION +The +.B sane-as6e +library implements a SANE (Scanner Access Now Easy) backend +that provides access to Artec AS6E flatbed scanner. +.B It requires the as6edriver program in order to operate. +The as6edriver program is +.B not +included with the SANE package. +It can be found at +.B http://as6edriver.sourceforge.net +. See the as6edriver documentation for technical information. +.PP + +.SH FILES +.B as6edriver +-driver program that controls the scanner. + +.SH BUGS + +.SH SEE ALSO +as6edriver(5) + +.SH AUTHOR +Eugene S. Weiss + +.SH EMAIL-CONTACT +yossarian@users.sourceforge.net