summaryrefslogtreecommitdiff
path: root/backend/hp.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/hp.c')
-rw-r--r--backend/hp.c1013
1 files changed, 1013 insertions, 0 deletions
diff --git a/backend/hp.c b/backend/hp.c
new file mode 100644
index 0000000..c85e40c
--- /dev/null
+++ b/backend/hp.c
@@ -0,0 +1,1013 @@
+/* sane - Scanner Access Now Easy.
+ Copyright (C) 1997 Geoffrey T. Dairiki
+ Support for HP PhotoSmart Photoscanner by Peter Kirchgessner
+ This file is part of the SANE package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ As a special exception, the authors of SANE give permission for
+ additional uses of the libraries contained in this release of SANE.
+
+ The exception is that, if you link a SANE library with other files
+ to produce an executable, this does not by itself cause the
+ resulting executable to be covered by the GNU General Public
+ License. Your use of that executable is in no way restricted on
+ account of linking the SANE library code into it.
+
+ This exception does not, however, invalidate any other reasons why
+ the executable file might be covered by the GNU General Public
+ License.
+
+ If you submit changes to SANE to the maintainers to be included in
+ a subsequent release, you agree by submitting the changes that
+ those changes may be distributed with this exception intact.
+
+ If you write modifications of your own for SANE, it is your choice
+ whether to permit this exception to apply to your modifications.
+ If you do not wish that, delete this exception notice.
+
+ This file is part of a SANE backend for HP Scanners supporting
+ HP Scanner Control Language (SCL).
+*/
+
+static char *hp_backend_version = "1.06";
+static char *hp_backend_revision = "$Revision$";
+/* Changes:
+
+ V 1.06:
+ $Log$
+ Revision 1.22 2008/11/26 21:21:25 kitno-guest
+ * backend/ *.[ch]: nearly every backend used V_MAJOR
+ instead of SANE_CURRENT_MAJOR in sane_init()
+ * backend/snapscan.c: remove EXPECTED_VERSION check
+ since new SANE standard is forward compatible
+
+ Revision 1.21 2004-10-04 18:09:05 kig-guest
+ Rename global function hp_init_openfd to sanei_hp_init_openfd
+
+ Revision 1.20 2004/03/27 13:52:39 kig-guest
+ Keep USB-connection open (was problem with Linux 2.6.x)
+
+
+ V 1.05:
+ Revision 1.19 2003/10/24 17:26:07 kig-guest
+ Use new sanei-thread-interface
+
+ Revision 1.18 2003/10/09 19:37:29 kig-guest
+ Redo when TEST UNIT READY failed
+ Redo when read returns with 0 bytes (non-SCSI only)
+ Bug #300241: fix invers image on 3c/4c/6100C at 10 bit depth
+
+ Revision 1.17 2003/10/06 19:54:07 kig-guest
+ Bug #300248: correct "Negatives" to "Negative" in option description
+
+
+ V 1.04, 24-Jul-2003, PK (peter@kirchgessner.net)
+ - Add internationalization
+
+ V 1.03, 14-Apr-2003, PK (peter@kirchgessner.net)
+ - check valp in call of sane_control_option()
+
+ V 1.02, 02-Feb-2003, PK (peter@kirchgessner.net)
+ - add OS/2-support by Franz Bakan
+
+ V 1.01, 06-Dec-2002, PK (peter@kirchgessner.net)
+ - add option dumb-read to work around problems
+ with BusLogic SCSI driver (error during device I/O)
+
+ V 1.00, 17-Nov-2002, PK (peter@kirchgessner.net)
+ - add libusb support
+
+ V 0.96, 05-Aug-2002, PK (peter@kirchgessner.net)
+ - check USB device names
+
+ V 0.95, 07-Jul-2001, PK (peter@kirchgessner.net)
+ - add support for active XPA
+ - check if paper in ADF for ADF scan
+ - add option lamp off
+ - remove some really unused parameters
+
+ V 0.94, 31-Dec-2000, PK (peter@kirchgessner.net)
+ - always switch off lamp after scan
+
+ V 0.93, 04-Dec-2000, PK (peter@kirchgessner.net)
+ - fix problem with ADF-support on ScanJet 6350 (and maybe others)
+
+ V 0.92, 03-Oct-2000, Rupert W. Curwen (rcurwen@uk.research.att.com):
+ - try to not allocate accessors twice (only for accessors
+ that have fixed length)
+ - fix problem with leaving connection open for some error conditions
+
+ V 0.91, 04-Sep-2000, David Paschal (paschal@rcsis.com):
+ - Added support for flatbed HP OfficeJets
+ - (PK) fix problem with cancel preview
+
+ V 0.90, 02-Sep-2000, PK:
+ - fix timing problem between killing child and writing to pipe
+ - change fprintf(stderr,...) to DBG
+ - change include <sane..> to "sane.." in hp.h
+ - change handling of options that have global effects.
+ i.e. if option scanmode is received (has global effect),
+ all options that "may change" are send to the scanner again.
+ This fixes a problem that --resolution specified infront of
+ --mode on command line of scanimage was ignored.
+ NOTE: This change does not allow to specify --depth 12 infront of
+ --mode color, because --depth is only enabled with --mode color.
+ - add depth greater 8 bits for mode grayscale
+ - add option for 8 bit output but 10/12 bit scanning
+ V 0.88, 25-Jul-2000, PK:
+ - remove inlines
+ V 0.88, 20-Jul-2000, PK:
+ - Use sanei_config_read()
+ - dont write chars < 32 to DBG
+ V 0.88, 09-Jul-2000, PK:
+ - Add front button support by Chris S. Cowles, Houston, Texas,
+ c_cowles@ieee.org
+ V 0.87, 28-Jun-2000, PK:
+ - ADF-support for ScanJet IIp
+ - Return error SANE_STATUS_NO_DOCS if no paper in ADF
+ V 0.86, 12-Feb-2000, PK:
+ - fix gcc warnings
+ - fix problems with bitdepths > 8
+ - allow hp_data_resize to be called with newsize==bufsiz
+ (Jens Heise, <heisbeee@calvados.zrz.TU-Berlin.DE>)
+ - add option enable-image-buffering
+ V 0.85, 30-Jan-2000, PK:
+ - correct and enhace data widths > 8 (Ewald de Wit <ewald@pobox.com>)
+ - enable data width for all scanners
+ - PhotoSmart: exposure "Off" changed to "Default"
+ - PhotoSmart: even if max. datawidth 24 is reported, allow 30 bits.
+ - change keyword -data-width to -depth and use value for bits per sample
+ - change keyword -halftone-type to -halftone-pattern
+ - change keyword -scantype to -source
+ - fix problem with multiple definition of sanei_debug_hp
+ V 0.83, 04-Jul-99, PK:
+ - reset scanner before downloading parameters (fixes problem
+ with sleep mode of scanners)
+ - fix problem with coredump if non-scanner HP SCSI devices
+ are connected (CDR)
+ - option scan-from-adf replaced by scantype normal/adf/xpa
+ - change value "Film strip" to "Film-strip" for option
+ --media-type
+ - PhotoScanner: allow only scanning at multiple of 300 dpi
+ for scanning slides/film strips. This also fixes a problem with the
+ preview which uses arbitrary resolutions.
+ - Marian Szebenyi: close pipe (endless loop on Digital UNIX)
+
+ V 0.82, 28-Feb-99, Ewald de Wit <ewald@pobox.com>:
+ - add options 'exposure time' and 'data width'
+
+ V 0.81, 11-Jan-99, PK:
+ - occasionally 'scan from ADF' was active for Photoscanner
+
+ V 0.80, 10-Jan-99, PK:
+ - fix problem with scan size for ADF-scan
+ (thanks to Christop Biardzki <cbi@allgaeu.org> for tests)
+ - add option "unload after scan" for HP PhotoScanner
+ - no blanks in command line options
+ - fix problem with segmentation fault for scanimage -d hp:/dev/sga
+ with /dev/sga not included in hp.conf
+
+ V 0.72, 25-Dec-98, PK:
+ - add patches from mike@easysw.com to fix problems:
+ - core dumps by memory alignment
+ - config file to accept matching devices (scsi HP)
+ - add simulation for brightness/contrast/custom gamma table
+ if not supported by scanner
+ - add configuration options for connect-...
+
+ V 0.72c, 04-Dec-98, PK:
+ - use sanei_pio
+ - try ADF support
+
+ V 0.72b, 29-Nov-98 James Carter <james@cs.york.ac.uk>, PK:
+ - try to add parallel scanner support
+
+ V 0.71, 14-Nov-98 PK:
+ - add HP 6200 C
+ - cleanup hp_scsi_s structure
+ - show calibrate button on photoscanner only for print media
+ - suppress halftone mode on photoscanner
+ - add media selection for photoscanner
+
+ V 0.70, 26-Jul-98 PK:
+ - Rename global symbols to sanei_...
+ Change filenames to hp-...
+ Use backend name hp
+
+ V 0.65, 18-Jul-98 PK:
+ - Dont use pwd.h for VACPP-Compiler to get home-directory,
+ check $SANE_HOME_XHP instead
+
+ V 0.64, 12-Jul-98 PK:
+ - only download calibration file for media = 1 (prints)
+ - Changes for VACPP-Compiler (check macros __IBMC__, __IBMCPP__)
+
+ V 0.63, 07-Jun-98 PK:
+ - fix problem with custom gamma table
+ - Add unload button
+
+ V 0.62, 25-May-98 PK:
+ - make it compilable under sane V 0.73
+
+ V 0.61, 28-Mar-98, Peter Kirchgessner <pkirchg@aol.com>:
+ - Add support for HP PhotoSmart Photoscanner
+ - Use more inquiries to see what the scanner supports
+ - Add options: calibrate/Mirror horizontal+vertical
+ - Upload/download calibration data
+*/
+
+#define VERSIO 8
+
+#include "../include/sane/config.h"
+#include "hp.h"
+
+#include <string.h>
+/* #include <sys/types.h> */
+/* #include "../include/sane/sane.h" */
+#include "../include/sane/sanei_config.h"
+#include "../include/sane/sanei_backend.h"
+#include "../include/sane/sanei_usb.h"
+#include "../include/sane/sanei_thread.h"
+/* #include "../include/sane/sanei_debug.h" */
+#include "hp-device.h"
+#include "hp-handle.h"
+
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+#ifndef NDEBUG
+#include <ctype.h>
+void
+sanei_hp_dbgdump (const void * bufp, size_t len)
+{
+ const hp_byte_t *buf = bufp;
+ int offset = 0;
+ int i;
+ char line[128], pt[32];
+
+ for (offset = 0; offset < (int)len; offset += 16)
+ {
+ sprintf (line," 0x%04X ", offset);
+ for (i = offset; i < offset + 16 && i < (int)len; i++)
+ {
+ sprintf (pt," %02X", buf[i]);
+ strcat (line, pt);
+ }
+ while (i++ < offset + 16)
+ strcat (line, " ");
+ strcat (line, " ");
+ for (i = offset; i < offset + 16 && i < (int)len; i++)
+ {
+ sprintf (pt, "%c", isprint(buf[i]) ? buf[i] : '.');
+ strcat (line, pt);
+ }
+ DBG(16,"%s\n",line);
+ }
+}
+
+#endif
+
+typedef struct info_list_el_s * HpDeviceInfoList;
+struct info_list_el_s
+{
+ HpDeviceInfoList next;
+ HpDeviceInfo info;
+};
+
+typedef struct device_list_el_s * HpDeviceList;
+struct device_list_el_s
+{
+ HpDeviceList next;
+ HpDevice dev;
+};
+
+/* Global state */
+static struct hp_global_s {
+ hp_bool_t is_up;
+ hp_bool_t config_read;
+
+ const SANE_Device ** devlist;
+
+ HpDeviceList device_list;
+ HpDeviceList handle_list;
+ HpDeviceInfoList infolist;
+
+ HpDeviceConfig config;
+} global;
+
+
+/* Get the info structure for a device. If not available in global list */
+/* add new entry and return it */
+static HpDeviceInfo *
+hp_device_info_create (const char *devname)
+
+{
+ HpDeviceInfoList *infolist = &(global.infolist);
+ HpDeviceInfoList infolistelement;
+ HpDeviceInfo *info;
+ int k, found;
+
+ if (!global.is_up) return 0;
+
+ found = 0;
+ infolistelement = 0;
+ info = 0;
+ while (*infolist)
+ {
+ infolistelement = *infolist;
+ info = &(infolistelement->info);
+ if (strcmp (info->devname, devname) == 0) /* Already in list ? */
+ {
+ found = 1;
+ break;
+ }
+ infolist = &(infolistelement->next);
+ }
+
+ if (found) /* Clear old entry */
+ {
+ memset (infolistelement, 0, sizeof (*infolistelement));
+ }
+ else /* New element */
+ {
+ infolistelement = (HpDeviceInfoList)
+ sanei_hp_allocz (sizeof (*infolistelement));
+ if (!infolistelement) return 0;
+ info = &(infolistelement->info);
+ *infolist = infolistelement;
+ }
+
+ k = sizeof (info->devname);
+ strncpy (info->devname, devname, k);
+ info->devname[k-1] = '\0';
+ info->max_model = -1;
+ info->active_xpa = -1;
+
+ return info;
+}
+
+static void
+hp_init_config (HpDeviceConfig *config)
+
+{
+ if (config)
+ {
+ config->connect = HP_CONNECT_SCSI;
+ config->use_scsi_request = 1;
+ config->use_image_buffering = 0;
+ config->got_connect_type = 0;
+ config->dumb_read = 0;
+ }
+}
+
+static HpDeviceConfig *
+hp_global_config_get (void)
+
+{
+ if (!global.is_up) return 0;
+ return &(global.config);
+}
+
+static SANE_Status
+hp_device_config_add (const char *devname)
+
+{
+ HpDeviceInfo *info;
+ HpDeviceConfig *config;
+
+ info = hp_device_info_create (devname);
+ if (!info) return SANE_STATUS_INVAL;
+
+ config = hp_global_config_get ();
+
+ if (config)
+ {
+ memcpy (&(info->config), config, sizeof (info->config));
+ info->config_is_up = 1;
+ }
+ else /* Initialize with default configuration */
+ {
+ DBG(3, "hp_device_config_add: No configuration found for device %s.\n\tUseing default\n",
+ devname);
+ hp_init_config (&(info->config));
+ info->config_is_up = 1;
+ }
+ return SANE_STATUS_GOOD;
+}
+
+HpDeviceInfo *
+sanei_hp_device_info_get (const char *devname)
+
+{
+ HpDeviceInfoList *infolist;
+ HpDeviceInfoList infolistelement;
+ HpDeviceInfo *info;
+ int retries = 1;
+
+ if (!global.is_up)
+ {
+ DBG(17, "sanei_hp_device_info_get: global.is_up = %d\n", (int)global.is_up);
+ return 0;
+ }
+
+ DBG(250, "sanei_hp_device_info_get: searching %s\n", devname);
+ do
+ {
+ infolist = &(global.infolist);
+ while (*infolist)
+ {
+ infolistelement = *infolist;
+ info = &(infolistelement->info);
+ DBG(250, "sanei_hp_device_info_get: check %s\n", info->devname);
+ if (strcmp (info->devname, devname) == 0) /* Found ? */
+ {
+ return info;
+ }
+ infolist = &(infolistelement->next);
+ }
+
+ /* No configuration found. Assume default */
+ DBG(1, "hp_device_info_get: device %s not configured. Using default\n",
+ devname);
+ if (hp_device_config_add (devname) != SANE_STATUS_GOOD)
+ return 0;
+ }
+ while (retries-- > 0);
+
+ return 0;
+}
+
+HpDevice
+sanei_hp_device_get (const char *devname)
+{
+ HpDeviceList ptr;
+
+ for (ptr = global.device_list; ptr; ptr = ptr->next)
+ if (strcmp(sanei_hp_device_sanedevice(ptr->dev)->name, devname) == 0)
+ return ptr->dev;
+
+ return 0;
+}
+
+static void
+hp_device_info_remove (void)
+{
+ HpDeviceInfoList next, infolistelement = global.infolist;
+ HpDeviceInfo *info;
+
+ if (!global.is_up) return;
+
+ while (infolistelement)
+ {
+ info = &(infolistelement->info);
+ next = infolistelement->next;
+ sanei_hp_free (infolistelement);
+ infolistelement = next;
+ }
+}
+
+static SANE_Status
+hp_device_list_add (HpDeviceList * list, HpDevice dev)
+{
+ HpDeviceList new = sanei_hp_alloc(sizeof(*new));
+
+ if (!new)
+ return SANE_STATUS_NO_MEM;
+ while (*list)
+ list = &(*list)->next;
+
+ *list = new;
+ new->next = 0;
+ new->dev = dev;
+ return SANE_STATUS_GOOD;
+}
+
+static SANE_Status
+hp_device_list_remove (HpDeviceList * list, HpDevice dev)
+{
+ HpDeviceList old;
+
+ while (*list && (*list)->dev != dev)
+ list = &(*list)->next;
+
+ if (!*list)
+ return SANE_STATUS_INVAL;
+
+ old = *list;
+ *list = (*list)->next;
+ sanei_hp_free(old);
+ return SANE_STATUS_GOOD;
+}
+
+static SANE_Status
+hp_handle_list_add (HpDeviceList * list, HpHandle h)
+{
+ return hp_device_list_add(list, (HpDevice)h);
+}
+
+static SANE_Status
+hp_handle_list_remove (HpDeviceList * list, HpHandle h)
+{
+ return hp_device_list_remove(list, (HpDevice)h);
+}
+
+
+
+
+static SANE_Status
+hp_init (void)
+{
+ memset(&global, 0, sizeof(global));
+ global.is_up++;
+ DBG(3, "hp_init: global.is_up = %d\n", (int)global.is_up);
+ return SANE_STATUS_GOOD;
+}
+
+static void
+hp_destroy (void)
+{
+ if (global.is_up)
+ {
+ /* Close open handles */
+ while (global.handle_list)
+ sane_close(global.handle_list->dev);
+
+ /* Remove device infos */
+ hp_device_info_remove ();
+
+ sanei_hp_free_all();
+ global.is_up = 0;
+ DBG(3, "hp_destroy: global.is_up = %d\n", (int)global.is_up);
+ }
+}
+
+static SANE_Status
+hp_get_dev (const char *devname, HpDevice* devp)
+{
+ HpDeviceList ptr;
+ HpDevice new;
+ const HpDeviceInfo *info;
+ char *connect;
+ HpConnect hp_connect;
+ SANE_Status status;
+
+ for (ptr = global.device_list; ptr; ptr = ptr->next)
+ if (strcmp(sanei_hp_device_sanedevice(ptr->dev)->name, devname) == 0)
+ {
+ if (devp)
+ *devp = ptr->dev;
+ return SANE_STATUS_GOOD;
+ }
+
+ info = sanei_hp_device_info_get (devname);
+ hp_connect = info->config.connect;
+
+ if (hp_connect == HP_CONNECT_SCSI) connect = "scsi";
+ else if (hp_connect == HP_CONNECT_DEVICE) connect = "device";
+ else if (hp_connect == HP_CONNECT_PIO) connect = "pio";
+ else if (hp_connect == HP_CONNECT_USB) connect = "usb";
+ else if (hp_connect == HP_CONNECT_RESERVE) connect = "reserve";
+ else connect = "unknown";
+
+ DBG(3, "hp_get_dev: New device %s, connect-%s, scsi-request=%lu\n",
+ devname, connect, (unsigned long)info->config.use_scsi_request);
+
+ if (!ptr)
+ {
+ status = sanei_hp_device_new (&new, devname);
+
+ if ( status != SANE_STATUS_GOOD )
+ return status;
+ }
+
+ if (devp)
+ *devp = new;
+
+ RETURN_IF_FAIL( hp_device_list_add(&global.device_list, new) );
+
+ return SANE_STATUS_GOOD;
+}
+
+static SANE_Status
+hp_attach (const char *devname)
+{
+ DBG(7,"hp_attach: \"%s\"\n", devname);
+ hp_device_config_add (devname);
+ return hp_get_dev (devname, 0);
+}
+
+static void
+hp_attach_matching_devices (HpDeviceConfig *config, const char *devname)
+{
+ static int usb_initialized = 0;
+
+ if (strncmp (devname, "usb", 3) == 0)
+ {
+ config->connect = HP_CONNECT_USB;
+ config->use_scsi_request = 0;
+ DBG(1,"hp_attach_matching_devices: usb attach matching \"%s\"\n",devname);
+ if (!usb_initialized)
+ {
+ sanei_usb_init ();
+ usb_initialized = 1;
+ }
+ sanei_usb_attach_matching_devices (devname, hp_attach);
+ }
+ else
+ {
+ DBG(1, "hp_attach_matching_devices: attach matching %s\n", devname);
+ sanei_config_attach_matching_devices (devname, hp_attach);
+ }
+}
+
+static SANE_Status
+hp_read_config (void)
+{
+ FILE * fp;
+ char buf[PATH_MAX], arg1[PATH_MAX], arg2[PATH_MAX], arg3[PATH_MAX];
+ int nl, nargs;
+ HpDeviceConfig *config, df_config, dev_config;
+ hp_bool_t is_df_config;
+ char cu_device[PATH_MAX];
+
+ if (!global.is_up)
+ return SANE_STATUS_INVAL;
+ if (global.config_read)
+ return SANE_STATUS_GOOD;
+
+ /* The default config will keep options set up until the first device is specified */
+ hp_init_config (&df_config);
+ config = &df_config;
+ is_df_config = 1;
+ cu_device[0] = '\0';
+
+ DBG(1, "hp_read_config: hp backend v%s/%s starts reading config file\n",
+ hp_backend_version, hp_backend_revision);
+
+ if ((fp = sanei_config_open(HP_CONFIG_FILE)) != 0)
+ {
+ while (sanei_config_read(buf, sizeof(buf), fp))
+ {
+ char *dev_name;
+
+ nl = strlen (buf);
+ while (nl > 0)
+ {
+ nl--;
+ if ( (buf[nl] == ' ') || (buf[nl] == '\t')
+ || (buf[nl] == '\r') || (buf[nl] == '\n'))
+ buf[nl] = '\0';
+ else
+ break;
+ }
+
+ DBG(1, "hp_read_config: processing line <%s>\n", buf);
+
+ nargs = sscanf (buf, "%s%s%s", arg1, arg2, arg3);
+ if ((nargs <= 0) || (arg1[0] == '#')) continue;
+
+ /* Option to process ? */
+ if ((strcmp (arg1, "option") == 0) && (nargs >= 2))
+ {
+ if (strcmp (arg2, "connect-scsi") == 0)
+ {
+ config->connect = HP_CONNECT_SCSI;
+ config->got_connect_type = 1;
+ }
+ else if (strcmp (arg2, "connect-device") == 0)
+ {
+ config->connect = HP_CONNECT_DEVICE;
+ config->got_connect_type = 1;
+ config->use_scsi_request = 0;
+ }
+ else if (strcmp (arg2, "connect-pio") == 0)
+ {
+ config->connect = HP_CONNECT_PIO;
+ config->got_connect_type = 1;
+ config->use_scsi_request = 0;
+ }
+ else if (strcmp (arg2, "connect-usb") == 0)
+ {
+ config->connect = HP_CONNECT_USB;
+ config->got_connect_type = 1;
+ config->use_scsi_request = 0;
+ }
+ else if (strcmp (arg2, "connect-reserve") == 0)
+ {
+ config->connect = HP_CONNECT_RESERVE;
+ config->got_connect_type = 1;
+ config->use_scsi_request = 0;
+ }
+ else if (strcmp (arg2, "disable-scsi-request") == 0)
+ {
+ config->use_scsi_request = 0;
+ }
+ else if (strcmp (arg2, "enable-image-buffering") == 0)
+ {
+ config->use_image_buffering = 1;
+ }
+ else if (strcmp (arg2, "dumb-read") == 0)
+ {
+ config->dumb_read = 1;
+ }
+ else
+ {
+ DBG(1,"hp_read_config: Invalid option %s\n", arg2);
+ }
+ }
+ else /* No option. This is the start of a new device */
+ {
+ if (is_df_config) /* Did we only read default configurations ? */
+ {
+ is_df_config = 0; /* Stop reading default config */
+ /* Initialize device config with default-config */
+ memcpy (&dev_config, &df_config, sizeof (dev_config));
+ config = &dev_config; /* Start reading a device config */
+ }
+ if (cu_device[0] != '\0') /* Did we work on a device ? */
+ {
+ memcpy (hp_global_config_get(), &dev_config,sizeof (dev_config));
+ hp_attach_matching_devices (hp_global_config_get(), cu_device);
+ cu_device[0] = '\0';
+ }
+
+ /* Initialize new device with default config */
+ memcpy (&dev_config, &df_config, sizeof (dev_config));
+
+ /* Cut off leading blanks of device name */
+ dev_name = buf+strspn (buf, " \t\n\r");
+ strcpy (cu_device, dev_name); /* Save the device name */
+ }
+ }
+ if (cu_device[0] != '\0') /* Did we work on a device ? */
+ {
+ memcpy (hp_global_config_get (), &dev_config, sizeof (dev_config));
+ DBG(1, "hp_read_config: attach %s\n", cu_device);
+ hp_attach_matching_devices (hp_global_config_get (), cu_device);
+ cu_device[0] = '\0';
+ }
+ fclose (fp);
+ DBG(1, "hp_read_config: reset to default config\n");
+ memcpy (hp_global_config_get (), &df_config, sizeof (df_config));
+ }
+ else
+ {
+ /* default to /dev/scanner instead of insisting on config file */
+ char *dev_name = "/dev/scanner";
+
+ memcpy (hp_global_config_get (), &df_config, sizeof (df_config));
+ hp_attach_matching_devices (hp_global_config_get (), dev_name);
+ }
+
+ global.config_read++;
+ return SANE_STATUS_GOOD;
+}
+
+static SANE_Status
+hp_update_devlist (void)
+{
+ HpDeviceList devp;
+ const SANE_Device **devlist;
+ int count = 0;
+
+ RETURN_IF_FAIL( hp_read_config() );
+
+ if (global.devlist)
+ sanei_hp_free(global.devlist);
+
+ for (devp = global.device_list; devp; devp = devp->next)
+ count++;
+
+ if (!(devlist = sanei_hp_alloc((count + 1) * sizeof(*devlist))))
+ return SANE_STATUS_NO_MEM;
+
+ global.devlist = devlist;
+
+ for (devp = global.device_list; devp; devp = devp->next)
+ *devlist++ = sanei_hp_device_sanedevice(devp->dev);
+ *devlist = 0;
+
+ return SANE_STATUS_GOOD;
+}
+
+
+/*
+ *
+ */
+
+SANE_Status
+sane_init (SANE_Int *version_code, SANE_Auth_Callback UNUSEDARG authorize)
+{SANE_Status status;
+
+ DBG_INIT();
+ DBG(3, "sane_init called\n");
+ sanei_thread_init ();
+
+ sanei_hp_init_openfd ();
+ hp_destroy();
+
+ if (version_code)
+ *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, VERSIO);
+
+ status = hp_init();
+ DBG(3, "sane_init will finish with %s\n", sane_strstatus (status));
+ return status;
+}
+
+void
+sane_exit (void)
+{
+ DBG(3, "sane_exit called\n");
+ hp_destroy();
+ DBG(3, "sane_exit will finish\n");
+}
+
+SANE_Status
+sane_get_devices (const SANE_Device ***device_list,
+ SANE_Bool UNUSEDARG local_only)
+{
+ DBG(3, "sane_get_devices called\n");
+
+ RETURN_IF_FAIL( hp_update_devlist() );
+ *device_list = global.devlist;
+ DBG(3, "sane_get_devices will finish with %s\n",
+ sane_strstatus (SANE_STATUS_GOOD));
+ return SANE_STATUS_GOOD;
+}
+
+SANE_Status
+sane_open (SANE_String_Const devicename, SANE_Handle *handle)
+{
+ HpDevice dev = 0;
+ HpHandle h;
+
+ DBG(3, "sane_open called\n");
+
+ RETURN_IF_FAIL( hp_read_config() );
+
+ if (devicename[0])
+ RETURN_IF_FAIL( hp_get_dev(devicename, &dev) );
+ else
+ {
+ /* empty devicname -> use first device */
+ if (global.device_list)
+ dev = global.device_list->dev;
+ }
+ if (!dev)
+ return SANE_STATUS_INVAL;
+
+ if (!(h = sanei_hp_handle_new(dev)))
+ return SANE_STATUS_NO_MEM;
+
+ RETURN_IF_FAIL( hp_handle_list_add(&global.handle_list, h) );
+
+ *handle = h;
+ DBG(3, "sane_open will finish with %s\n", sane_strstatus (SANE_STATUS_GOOD));
+ return SANE_STATUS_GOOD;
+}
+
+void
+sane_close (SANE_Handle handle)
+{
+ HpHandle h = handle;
+
+ DBG(3, "sane_close called\n");
+
+ if (!FAILED( hp_handle_list_remove(&global.handle_list, h) ))
+ sanei_hp_handle_destroy(h);
+
+ DBG(3, "sane_close will finish\n");
+}
+
+const SANE_Option_Descriptor *
+sane_get_option_descriptor (SANE_Handle handle, SANE_Int optnum)
+{
+ HpHandle h = handle;
+ const SANE_Option_Descriptor *optd;
+
+ DBG(10, "sane_get_option_descriptor called\n");
+
+ optd = sanei_hp_handle_saneoption(h, optnum);
+
+ DBG(10, "sane_get_option_descriptor will finish\n");
+
+ return optd;
+}
+
+SANE_Status
+sane_control_option (SANE_Handle handle, SANE_Int optnum,
+ SANE_Action action, void *valp, SANE_Int *info)
+{
+ HpHandle h = handle;
+ SANE_Status status;
+
+ DBG(10, "sane_control_option called\n");
+
+ status = sanei_hp_handle_control(h, optnum, action, valp, info);
+
+ DBG(10, "sane_control_option will finish with %s\n",
+ sane_strstatus (status));
+ return status;
+}
+
+SANE_Status
+sane_get_parameters (SANE_Handle handle, SANE_Parameters *params)
+{
+ HpHandle h = handle;
+ SANE_Status status;
+
+ DBG(10, "sane_get_parameters called\n");
+
+ status = sanei_hp_handle_getParameters(h, params);
+
+ DBG(10, "sane_get_parameters will finish with %s\n",
+ sane_strstatus (status));
+ return status;
+}
+
+SANE_Status
+sane_start (SANE_Handle handle)
+{
+ HpHandle h = handle;
+ SANE_Status status;
+
+ DBG(3, "sane_start called\n");
+
+ status = sanei_hp_handle_startScan(h);
+
+ DBG(3, "sane_start will finish with %s\n", sane_strstatus (status));
+ return status;
+}
+
+SANE_Status
+sane_read (SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len)
+{
+ HpHandle h = handle;
+ size_t length = max_len;
+ SANE_Status status;
+
+ DBG(16, "sane_read called\n");
+
+ status = sanei_hp_handle_read(h, buf, &length);
+ *len = length;
+
+ DBG(16, "sane_read will finish with %s\n", sane_strstatus (status));
+ return status;
+}
+
+void
+sane_cancel (SANE_Handle handle)
+{
+ HpHandle h = handle;
+
+ DBG(3, "sane_cancel called\n");
+
+ sanei_hp_handle_cancel(h);
+
+ DBG(3, "sane_cancel will finish\n");
+}
+
+SANE_Status
+sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
+{
+ HpHandle h = handle;
+ SANE_Status status;
+
+ DBG(3, "sane_set_io_mode called\n");
+
+ status = sanei_hp_handle_setNonblocking(h, non_blocking);
+
+ DBG(3, "sane_set_io_mode will finish with %s\n",
+ sane_strstatus (status));
+ return status;
+}
+
+SANE_Status
+sane_get_select_fd (SANE_Handle handle, SANE_Int *fd)
+{
+ HpHandle h = handle;
+ SANE_Status status;
+
+ DBG(10, "sane_get_select_fd called\n");
+
+ status = sanei_hp_handle_getPipefd(h, fd);
+
+ DBG(10, "sane_get_select_fd will finish with %s\n",
+ sane_strstatus (status));
+ return status;
+}