summaryrefslogtreecommitdiff
path: root/backend/hp5400_sane.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-10-06 14:00:40 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-10-06 14:00:40 +0200
commit6e9c41a892ed0e0da326e0278b3221ce3f5713b8 (patch)
tree2e301d871bbeeb44aa57ff9cc070fcf3be484487 /backend/hp5400_sane.c
Initial import of sane-backends version 1.0.24-1.2
Diffstat (limited to 'backend/hp5400_sane.c')
-rw-r--r--backend/hp5400_sane.c1022
1 files changed, 1022 insertions, 0 deletions
diff --git a/backend/hp5400_sane.c b/backend/hp5400_sane.c
new file mode 100644
index 0000000..e5fdf43
--- /dev/null
+++ b/backend/hp5400_sane.c
@@ -0,0 +1,1022 @@
+/* sane - Scanner Access Now Easy.
+ Copyright (C) 2003 Martijn van Oosterhout <kleptog@svana.org>
+ Copyright (C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
+
+ Originally copied from HP3300 testtools. Original notice follows:
+
+ Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl)
+
+ 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.
+*/
+
+
+/*
+ SANE interface for hp54xx scanners. Prototype.
+ Parts of this source were inspired by other backends.
+*/
+
+#include "../include/sane/config.h"
+
+/* definitions for debug */
+#include "hp5400_debug.h"
+
+#include "../include/sane/sane.h"
+#include "../include/sane/sanei.h"
+#include "../include/sane/sanei_backend.h"
+#include "../include/sane/sanei_config.h"
+#include "../include/sane/saneopts.h"
+#include "../include/sane/sanei_usb.h"
+
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* memcpy */
+#include <stdio.h>
+#include <errno.h>
+
+#define HP5400_CONFIG_FILE "hp5400.conf"
+
+#include "hp5400.h"
+
+/* includes for data transfer methods */
+#include "hp5400.h"
+
+#ifdef STANDALONE
+#include "hp5400_scanner.h"
+#endif
+
+#if defined(LINUX_USB_SUPPORT)
+ #include "hp5400_linux.c"
+#endif
+#if defined(USCANNER_SUPPORT)
+ #include "hp5400_uscanner.c"
+#endif
+#if defined(LIBUSB_SUPPORT)
+ #include "hp5400_libusb.c"
+#endif
+#if defined(LIBIEEE1284_SUPPORT)
+ #include "hp5400_ieee1284.c"
+#endif
+
+
+
+/* other definitions */
+#ifndef min
+#define min(A,B) (((A)<(B)) ? (A) : (B))
+#endif
+#ifndef max
+#define max(A,B) (((A)>(B)) ? (A) : (B))
+#endif
+
+#define TRUE 1
+#define FALSE 0
+
+#define MM_TO_PIXEL(_mm_, _dpi_) ((_mm_) * (_dpi_) / 25.4)
+#define PIXEL_TO_MM(_pixel_, _dpi_) ((_pixel_) * 25.4 / (_dpi_))
+
+#define NUM_GAMMA_ENTRIES 65536
+
+
+/* options enumerator */
+typedef enum
+{
+ optCount = 0,
+
+ optGroupGeometry,
+ optTLX, optTLY, optBRX, optBRY,
+ optDPI,
+
+ optGroupImage,
+
+ optGammaTableRed, /* Gamma Tables */
+ optGammaTableGreen,
+ optGammaTableBlue,
+
+ optLast, /* Disable the offset code */
+
+ optGroupMisc,
+ optOffsetX, optOffsetY
+
+
+/* put temporarily disabled options here after optLast */
+/*
+ optLamp,
+*/
+
+}
+EOptionIndex;
+
+typedef union
+{
+ SANE_Word w;
+ SANE_Word *wa; /* word array */
+ SANE_String s;
+}
+TOptionValue;
+
+
+typedef struct
+{
+ SANE_Option_Descriptor aOptions[optLast];
+ TOptionValue aValues[optLast];
+
+ TScanParams ScanParams;
+ THWParams HWParams;
+
+ TDataPipe DataPipe;
+ int iLinesLeft;
+
+ SANE_Int *aGammaTableR; /* a 16-to-16 bit color lookup table */
+ SANE_Int *aGammaTableG; /* a 16-to-16 bit color lookup table */
+ SANE_Int *aGammaTableB; /* a 16-to-16 bit color lookup table */
+
+ int fScanning; /* TRUE if actively scanning */
+ int fCanceled;
+}
+TScanner;
+
+
+/* linked list of SANE_Device structures */
+typedef struct TDevListEntry
+{
+ struct TDevListEntry *pNext;
+ SANE_Device dev;
+ char* devname;
+}
+TDevListEntry;
+
+
+
+/* Device filename for USB access */
+char usb_devfile[128];
+
+static TDevListEntry *_pFirstSaneDev = 0;
+static int iNumSaneDev = 0;
+
+
+static const SANE_Device **_pSaneDevList = 0;
+
+/* option constraints */
+static const SANE_Range rangeGammaTable = {0, 65535, 1};
+#ifdef SUPPORT_2400_DPI
+static const SANE_Int setResolutions[] = {6, 75, 150, 300, 600, 1200, 2400};
+#else
+static const SANE_Int setResolutions[] = {5, 75, 150, 300, 600, 1200};
+#endif
+static const SANE_Range rangeXmm = {0, 220, 1};
+static const SANE_Range rangeYmm = {0, 300, 1};
+static const SANE_Range rangeXoffset = {0, 20, 1};
+static const SANE_Range rangeYoffset = {0, 70, 1};
+static const SANE_Int offsetX = 5;
+static const SANE_Int offsetY = 52;
+
+
+static void _InitOptions(TScanner *s)
+{
+ int i, j;
+ SANE_Option_Descriptor *pDesc;
+ TOptionValue *pVal;
+
+ /* set a neutral gamma */
+ if( s->aGammaTableR == NULL ) /* Not yet allocated */
+ {
+ s->aGammaTableR = malloc( NUM_GAMMA_ENTRIES * sizeof( SANE_Int ) );
+ s->aGammaTableG = malloc( NUM_GAMMA_ENTRIES * sizeof( SANE_Int ) );
+ s->aGammaTableB = malloc( NUM_GAMMA_ENTRIES * sizeof( SANE_Int ) );
+
+ for (j = 0; j < NUM_GAMMA_ENTRIES; j++) {
+ s->aGammaTableR[j] = j;
+ s->aGammaTableG[j] = j;
+ s->aGammaTableB[j] = j;
+ }
+ }
+
+ for (i = optCount; i < optLast; i++) {
+
+ pDesc = &s->aOptions[i];
+ pVal = &s->aValues[i];
+
+ /* defaults */
+ pDesc->name = "";
+ pDesc->title = "";
+ pDesc->desc = "";
+ pDesc->type = SANE_TYPE_INT;
+ pDesc->unit = SANE_UNIT_NONE;
+ pDesc->size = sizeof(SANE_Word);
+ pDesc->constraint_type = SANE_CONSTRAINT_NONE;
+ pDesc->cap = 0;
+
+ switch (i) {
+
+ case optCount:
+ pDesc->title = SANE_TITLE_NUM_OPTIONS;
+ pDesc->desc = SANE_DESC_NUM_OPTIONS;
+ pDesc->cap = SANE_CAP_SOFT_DETECT;
+ pVal->w = (SANE_Word)optLast;
+ break;
+
+ case optGroupGeometry:
+ pDesc->title = "Geometry";
+ pDesc->type = SANE_TYPE_GROUP;
+ pDesc->size = 0;
+ break;
+
+ case optTLX:
+ pDesc->name = SANE_NAME_SCAN_TL_X;
+ pDesc->title = SANE_TITLE_SCAN_TL_X;
+ pDesc->desc = SANE_DESC_SCAN_TL_X;
+ pDesc->unit = SANE_UNIT_MM;
+ pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
+ pDesc->constraint.range = &rangeXmm;
+ pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ pVal->w = rangeXmm.min + offsetX;
+ break;
+
+ case optTLY:
+ pDesc->name = SANE_NAME_SCAN_TL_Y;
+ pDesc->title = SANE_TITLE_SCAN_TL_Y;
+ pDesc->desc = SANE_DESC_SCAN_TL_Y;
+ pDesc->unit = SANE_UNIT_MM;
+ pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
+ pDesc->constraint.range = &rangeYmm;
+ pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ pVal->w = rangeYmm.min + offsetY;
+ break;
+
+ case optBRX:
+ pDesc->name = SANE_NAME_SCAN_BR_X;
+ pDesc->title = SANE_TITLE_SCAN_BR_X;
+ pDesc->desc = SANE_DESC_SCAN_BR_X;
+ pDesc->unit = SANE_UNIT_MM;
+ pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
+ pDesc->constraint.range = &rangeXmm;
+ pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ pVal->w = rangeXmm.max + offsetX;
+ break;
+
+ case optBRY:
+ pDesc->name = SANE_NAME_SCAN_BR_Y;
+ pDesc->title = SANE_TITLE_SCAN_BR_Y;
+ pDesc->desc = SANE_DESC_SCAN_BR_Y;
+ pDesc->unit = SANE_UNIT_MM;
+ pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
+ pDesc->constraint.range = &rangeYmm;
+ pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ pVal->w = rangeYmm.max + offsetY;
+ break;
+
+ case optDPI:
+ pDesc->name = SANE_NAME_SCAN_RESOLUTION;
+ pDesc->title = SANE_TITLE_SCAN_RESOLUTION;
+ pDesc->desc = SANE_DESC_SCAN_RESOLUTION;
+ pDesc->unit = SANE_UNIT_DPI;
+ pDesc->constraint_type = SANE_CONSTRAINT_WORD_LIST;
+ pDesc->constraint.word_list = setResolutions;
+ pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ pVal->w = setResolutions[1];
+ break;
+
+ case optGroupImage:
+ pDesc->title = SANE_I18N("Image");
+ pDesc->type = SANE_TYPE_GROUP;
+ pDesc->size = 0;
+ break;
+
+ case optGammaTableRed:
+ pDesc->name = SANE_NAME_GAMMA_VECTOR_R;
+ pDesc->title = SANE_TITLE_GAMMA_VECTOR_R;
+ pDesc->desc = SANE_DESC_GAMMA_VECTOR_R;
+ pDesc->size = NUM_GAMMA_ENTRIES * sizeof( SANE_Int );
+ pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
+ pDesc->constraint.range = &rangeGammaTable;
+ pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ pVal->wa = s->aGammaTableR;
+ break;
+
+ case optGammaTableGreen:
+ pDesc->name = SANE_NAME_GAMMA_VECTOR_G;
+ pDesc->title = SANE_TITLE_GAMMA_VECTOR_G;
+ pDesc->desc = SANE_DESC_GAMMA_VECTOR_G;
+ pDesc->size = NUM_GAMMA_ENTRIES * sizeof( SANE_Int );
+ pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
+ pDesc->constraint.range = &rangeGammaTable;
+ pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ pVal->wa = s->aGammaTableG;
+ break;
+
+ case optGammaTableBlue:
+ pDesc->name = SANE_NAME_GAMMA_VECTOR_B;
+ pDesc->title = SANE_TITLE_GAMMA_VECTOR_B;
+ pDesc->desc = SANE_DESC_GAMMA_VECTOR_B;
+ pDesc->size = NUM_GAMMA_ENTRIES * sizeof( SANE_Int );
+ pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
+ pDesc->constraint.range = &rangeGammaTable;
+ pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ pVal->wa = s->aGammaTableB;
+ break;
+
+ case optGroupMisc:
+ pDesc->title = SANE_I18N("Miscellaneous");
+ pDesc->type = SANE_TYPE_GROUP;
+ pDesc->size = 0;
+ break;
+
+ case optOffsetX:
+ pDesc->title = SANE_I18N("offset X");
+ pDesc->desc = SANE_I18N("Hardware internal X position of the scanning area.");
+ pDesc->unit = SANE_UNIT_MM;
+ pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
+ pDesc->constraint.range = &rangeXoffset;
+ pDesc->cap = SANE_CAP_SOFT_SELECT;
+ pVal->w = offsetX;
+ break;
+
+ case optOffsetY:
+ pDesc->title = SANE_I18N("offset Y");
+ pDesc->desc = SANE_I18N("Hardware internal Y position of the scanning area.");
+ pDesc->unit = SANE_UNIT_MM;
+ pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
+ pDesc->constraint.range = &rangeYoffset;
+ pDesc->cap = SANE_CAP_SOFT_SELECT;
+ pVal->w = offsetY;
+ break;
+
+
+#if 0
+ case optLamp:
+ pDesc->name = "lamp";
+ pDesc->title = SANE_I18N("Lamp status");
+ pDesc->desc = SANE_I18N("Switches the lamp on or off.");
+ pDesc->type = SANE_TYPE_BOOL;
+ pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ /* switch the lamp on when starting for first the time */
+ pVal->w = SANE_TRUE;
+ break;
+#endif
+#if 0
+ case optCalibrate:
+ pDesc->name = "calibrate";
+ pDesc->title = SANE_I18N("Calibrate");
+ pDesc->desc = SANE_I18N("Calibrates for black and white level.");
+ pDesc->type = SANE_TYPE_BUTTON;
+ pDesc->cap = SANE_CAP_SOFT_SELECT;
+ pDesc->size = 0;
+ break;
+#endif
+ default:
+ HP5400_DBG(DBG_ERR, "Uninitialised option %d\n", i);
+ break;
+ }
+ }
+}
+
+
+static int _ReportDevice(TScannerModel *pModel, const char *pszDeviceName)
+{
+ TDevListEntry *pNew, *pDev;
+
+ HP5400_DBG(DBG_MSG, "hp5400: _ReportDevice '%s'\n", pszDeviceName);
+
+ pNew = malloc(sizeof(TDevListEntry));
+ if (!pNew) {
+ HP5400_DBG(DBG_ERR, "no mem\n");
+ return -1;
+ }
+
+ /* add new element to the end of the list */
+ if (_pFirstSaneDev == NULL) {
+ _pFirstSaneDev = pNew;
+ }
+ else {
+ for (pDev = _pFirstSaneDev; pDev->pNext; pDev = pDev->pNext) {
+ ;
+ }
+ pDev->pNext = pNew;
+ }
+
+ /* fill in new element */
+ pNew->pNext = 0;
+ /* we use devname to avoid having to free a const
+ * pointer */
+ pNew->devname = (char*)strdup(pszDeviceName);
+ pNew->dev.name = pNew->devname;
+ pNew->dev.vendor = pModel->pszVendor;
+ pNew->dev.model = pModel->pszName;
+ pNew->dev.type = "flatbed scanner";
+
+ iNumSaneDev++;
+
+ return 0;
+}
+
+static SANE_Status
+attach_one_device (SANE_String_Const devname)
+{
+ const char * filename = (const char*) devname;
+ if (HP5400Detect (filename, _ReportDevice) < 0)
+ {
+ HP5400_DBG (DBG_MSG, "attach_one_device: couldn't attach %s\n", devname);
+ return SANE_STATUS_INVAL;
+ }
+ HP5400_DBG (DBG_MSG, "attach_one_device: attached %s successfully\n", devname);
+ return SANE_STATUS_GOOD;
+}
+
+
+/*****************************************************************************/
+
+SANE_Status
+sane_init (SANE_Int * piVersion, SANE_Auth_Callback pfnAuth)
+{
+ FILE *conf_fp; /* Config file stream */
+ SANE_Char line[PATH_MAX];
+ SANE_Char *str = NULL;
+ SANE_String_Const proper_str;
+ int nline = 0;
+
+ /* prevent compiler from complaing about unused parameters */
+ pfnAuth = pfnAuth;
+
+ strcpy(usb_devfile, "/dev/usb/scanner0");
+ _pFirstSaneDev = 0;
+ iNumSaneDev = 0;
+
+ InitHp5400_internal();
+
+
+ DBG_INIT ();
+
+ HP5400_DBG (DBG_MSG, "sane_init: SANE hp5400 backend version %d.%d-%d (from %s)\n",
+ SANE_CURRENT_MAJOR, V_MINOR, BUILD, PACKAGE_STRING);
+
+ sanei_usb_init ();
+
+ conf_fp = sanei_config_open (HP5400_CONFIG_FILE);
+
+ iNumSaneDev = 0;
+
+ if (conf_fp)
+ {
+ HP5400_DBG (DBG_MSG, "Reading config file\n");
+
+ while (sanei_config_read (line, sizeof (line), conf_fp))
+ {
+ ++nline;
+
+ if (str)
+ {
+ free (str);
+ }
+
+ proper_str = sanei_config_get_string (line, &str);
+
+ /* Discards white lines and comments */
+ if (!str || proper_str == line || str[0] == '#')
+ {
+ HP5400_DBG (DBG_MSG, "Discarding line %d\n", nline);
+ }
+ else
+ {
+ /* If line's not blank or a comment, then it's the device
+ * filename or a usb directive. */
+ HP5400_DBG (DBG_MSG, "Trying to attach %s\n", line);
+ sanei_usb_attach_matching_devices (line, attach_one_device);
+ }
+ } /* while */
+ fclose (conf_fp);
+ }
+ else
+ {
+ HP5400_DBG (DBG_ERR, "Unable to read config file \"%s\": %s\n",
+ HP5400_CONFIG_FILE, strerror (errno));
+ HP5400_DBG (DBG_MSG, "Using default built-in values\n");
+ attach_one_device (usb_devfile);
+ }
+
+ if (piVersion != NULL)
+ {
+ *piVersion = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, BUILD);
+ }
+
+
+ return SANE_STATUS_GOOD;
+}
+
+
+void
+sane_exit (void)
+{
+ TDevListEntry *pDev, *pNext;
+ HP5400_DBG (DBG_MSG, "sane_exit\n");
+
+ /* free device list memory */
+ if (_pSaneDevList)
+ {
+ for (pDev = _pFirstSaneDev; pDev; pDev = pNext)
+ {
+ pNext = pDev->pNext;
+ free (pDev->devname);
+ /* pDev->dev.name is the same pointer that pDev->devname */
+ free (pDev);
+ }
+ _pFirstSaneDev = 0;
+ free (_pSaneDevList);
+ _pSaneDevList = 0;
+ }
+
+
+ FreeHp5400_internal();
+}
+
+
+SANE_Status
+sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
+{
+ TDevListEntry *pDev;
+ int i;
+
+ HP5400_DBG (DBG_MSG, "sane_get_devices\n");
+
+ local_only = local_only;
+
+ if (_pSaneDevList)
+ {
+ free (_pSaneDevList);
+ }
+
+ _pSaneDevList = malloc (sizeof (*_pSaneDevList) * (iNumSaneDev + 1));
+ if (!_pSaneDevList)
+ {
+ HP5400_DBG (DBG_MSG, "no mem\n");
+ return SANE_STATUS_NO_MEM;
+ }
+ i = 0;
+ for (pDev = _pFirstSaneDev; pDev; pDev = pDev->pNext)
+ {
+ _pSaneDevList[i++] = &pDev->dev;
+ }
+ _pSaneDevList[i++] = 0; /* last entry is 0 */
+
+ *device_list = _pSaneDevList;
+
+ return SANE_STATUS_GOOD;
+}
+
+
+SANE_Status
+sane_open (SANE_String_Const name, SANE_Handle * h)
+{
+ TScanner *s;
+
+ HP5400_DBG (DBG_MSG, "sane_open: %s\n", name);
+
+ /* check the name */
+ if (strlen (name) == 0)
+ {
+ /* default to first available device */
+ name = _pFirstSaneDev->dev.name;
+ }
+
+ s = malloc (sizeof (TScanner));
+ if (!s)
+ {
+ HP5400_DBG (DBG_MSG, "malloc failed\n");
+ return SANE_STATUS_NO_MEM;
+ }
+
+ memset (s, 0, sizeof (TScanner)); /* Clear everything to zero */
+ if (HP5400Open (&s->HWParams, name) < 0)
+ {
+ /* is this OK ? */
+ HP5400_DBG (DBG_ERR, "HP5400Open failed\n");
+ free ((void *) s);
+ return SANE_STATUS_INVAL; /* is this OK? */
+ }
+ HP5400_DBG (DBG_MSG, "Handle=%d\n", s->HWParams.iXferHandle);
+ _InitOptions (s);
+ *h = s;
+
+ /* Turn on lamp by default at startup */
+/* SetLamp(&s->HWParams, TRUE); */
+
+ return SANE_STATUS_GOOD;
+}
+
+
+void
+sane_close (SANE_Handle h)
+{
+ TScanner *s;
+
+ HP5400_DBG (DBG_MSG, "sane_close\n");
+
+ s = (TScanner *) h;
+
+ /* turn of scanner lamp */
+ SetLamp (&s->HWParams, FALSE);
+
+ /* close scanner */
+ HP5400Close (&s->HWParams);
+
+ /* free scanner object memory */
+ free ((void *) s);
+}
+
+
+const SANE_Option_Descriptor *
+sane_get_option_descriptor (SANE_Handle h, SANE_Int n)
+{
+ TScanner *s;
+
+ HP5400_DBG (DBG_MSG, "sane_get_option_descriptor %d\n", n);
+
+ if ((n < optCount) || (n >= optLast))
+ {
+ return NULL;
+ }
+
+ s = (TScanner *) h;
+ return &s->aOptions[n];
+}
+
+
+SANE_Status
+sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
+ void *pVal, SANE_Int * pInfo)
+{
+ TScanner *s;
+ SANE_Int info;
+
+ HP5400_DBG (DBG_MSG, "sane_control_option: option %d, action %d\n", n, Action);
+
+ s = (TScanner *) h;
+ info = 0;
+
+ switch (Action)
+ {
+ case SANE_ACTION_GET_VALUE:
+ switch (n)
+ {
+
+ /* Get options of type SANE_Word */
+ case optBRX:
+ case optTLX:
+ *(SANE_Word *) pVal = s->aValues[n].w; /* Not needed anymore - s->aValues[optOffsetX].w; */
+ HP5400_DBG (DBG_MSG,
+ "sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n,
+ *(SANE_Word *) pVal);
+ break;
+
+ case optBRY:
+ case optTLY:
+ *(SANE_Word *) pVal = s->aValues[n].w; /* Not needed anymore - - s->aValues[optOffsetY].w; */
+ HP5400_DBG (DBG_MSG,
+ "sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n,
+ *(SANE_Word *) pVal);
+ break;
+
+ case optOffsetX:
+ case optOffsetY:
+ case optCount:
+ case optDPI:
+ HP5400_DBG (DBG_MSG,
+ "sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n,
+ (int) s->aValues[n].w);
+ *(SANE_Word *) pVal = s->aValues[n].w;
+ break;
+
+ /* Get options of type SANE_Word array */
+ case optGammaTableRed:
+ case optGammaTableGreen:
+ case optGammaTableBlue:
+ HP5400_DBG (DBG_MSG, "Reading gamma table\n");
+ memcpy (pVal, s->aValues[n].wa, s->aOptions[n].size);
+ break;
+
+#if 0
+ /* Get options of type SANE_Bool */
+ case optLamp:
+ GetLamp (&s->HWParams, &fLampIsOn);
+ *(SANE_Bool *) pVal = fLampIsOn;
+ break;
+#endif
+#if 0
+ case optCalibrate:
+ /* although this option has nothing to read,
+ it's added here to avoid a warning when running scanimage --help */
+ break;
+#endif
+ default:
+ HP5400_DBG (DBG_MSG, "SANE_ACTION_GET_VALUE: Invalid option (%d)\n", n);
+ }
+ break;
+
+
+ case SANE_ACTION_SET_VALUE:
+ if (s->fScanning)
+ {
+ HP5400_DBG (DBG_ERR,
+ "sane_control_option: SANE_ACTION_SET_VALUE not allowed during scan\n");
+ return SANE_STATUS_INVAL;
+ }
+ switch (n)
+ {
+
+ case optCount:
+ return SANE_STATUS_INVAL;
+ break;
+
+ case optBRX:
+ case optTLX:
+ info |= SANE_INFO_RELOAD_PARAMS;
+ s->ScanParams.iLines = 0; /* Forget actual image settings */
+ s->aValues[n].w = *(SANE_Word *) pVal; /* Not needed anymore - + s->aValues[optOffsetX].w; */
+ break;
+
+ case optBRY:
+ case optTLY:
+ info |= SANE_INFO_RELOAD_PARAMS;
+ s->ScanParams.iLines = 0; /* Forget actual image settings */
+ s->aValues[n].w = *(SANE_Word *) pVal; /* Not needed anymore - + s->aValues[optOffsetY].w; */
+ break;
+ case optDPI:
+ info |= SANE_INFO_RELOAD_PARAMS;
+ s->ScanParams.iLines = 0; /* Forget actual image settings */
+#ifdef SUPPORT_2400_DPI
+ (s->aValues[n].w) = *(SANE_Word *) pVal;
+#else
+ (s->aValues[n].w) = min (1200, *(SANE_Word *) pVal);
+#endif
+ break;
+
+ case optGammaTableRed:
+ case optGammaTableGreen:
+ case optGammaTableBlue:
+ HP5400_DBG (DBG_MSG, "Writing gamma table\n");
+ memcpy (s->aValues[n].wa, pVal, s->aOptions[n].size);
+ break;
+/*
+ case optLamp:
+ fVal = *(SANE_Bool *)pVal;
+ HP5400_DBG(DBG_MSG, "lamp %s\n", fVal ? "on" : "off");
+ SetLamp(&s->HWParams, fVal);
+ break;
+*/
+#if 0
+ case optCalibrate:
+/* SimpleCalib(&s->HWParams); */
+ break;
+#endif
+ default:
+ HP5400_DBG (DBG_ERR, "SANE_ACTION_SET_VALUE: Invalid option (%d)\n", n);
+ }
+ if (pInfo != NULL)
+ {
+ *pInfo = info;
+ }
+ break;
+
+ case SANE_ACTION_SET_AUTO:
+ return SANE_STATUS_UNSUPPORTED;
+
+
+ default:
+ HP5400_DBG (DBG_ERR, "Invalid action (%d)\n", Action);
+ return SANE_STATUS_INVAL;
+ }
+
+ return SANE_STATUS_GOOD;
+}
+
+
+
+SANE_Status
+sane_get_parameters (SANE_Handle h, SANE_Parameters * p)
+{
+ TScanner *s;
+ HP5400_DBG (DBG_MSG, "sane_get_parameters\n");
+
+ s = (TScanner *) h;
+
+ /* first do some checks */
+ if (s->aValues[optTLX].w >= s->aValues[optBRX].w)
+ {
+ HP5400_DBG (DBG_ERR, "TLX should be smaller than BRX\n");
+ return SANE_STATUS_INVAL; /* proper error code? */
+ }
+ if (s->aValues[optTLY].w >= s->aValues[optBRY].w)
+ {
+ HP5400_DBG (DBG_ERR, "TLY should be smaller than BRY\n");
+ return SANE_STATUS_INVAL; /* proper error code? */
+ }
+
+ /* return the data */
+ p->format = SANE_FRAME_RGB;
+ p->last_frame = SANE_TRUE;
+
+ p->depth = 8;
+ if (s->ScanParams.iLines) /* Initialised by doing a scan */
+ {
+ p->pixels_per_line = s->ScanParams.iBytesPerLine / 3;
+ p->lines = s->ScanParams.iLines;
+ p->bytes_per_line = s->ScanParams.iBytesPerLine;
+ }
+ else
+ {
+ p->lines = MM_TO_PIXEL (s->aValues[optBRY].w - s->aValues[optTLY].w,
+ s->aValues[optDPI].w);
+ p->pixels_per_line =
+ MM_TO_PIXEL (s->aValues[optBRX].w - s->aValues[optTLX].w,
+ s->aValues[optDPI].w);
+ p->bytes_per_line = p->pixels_per_line * 3;
+ }
+
+ return SANE_STATUS_GOOD;
+}
+
+#define BUFFER_READ_HEADER_SIZE 32
+
+SANE_Status
+sane_start (SANE_Handle h)
+{
+ TScanner *s;
+ SANE_Parameters par;
+
+ HP5400_DBG (DBG_MSG, "sane_start\n");
+
+ s = (TScanner *) h;
+
+ if (sane_get_parameters (h, &par) != SANE_STATUS_GOOD)
+ {
+ HP5400_DBG (DBG_MSG, "Invalid scan parameters (sane_get_parameters)\n");
+ return SANE_STATUS_INVAL;
+ }
+ s->iLinesLeft = par.lines;
+
+ /* fill in the scanparams using the option values */
+ s->ScanParams.iDpi = s->aValues[optDPI].w;
+ s->ScanParams.iLpi = s->aValues[optDPI].w;
+
+ /* Guessing here. 75dpi => 1, 2400dpi => 32 */
+ /* s->ScanParams.iColourOffset = s->aValues[optDPI].w / 75; */
+ /* now we don't need correction => corrected by scan request type ? */
+ s->ScanParams.iColourOffset = 0;
+
+ s->ScanParams.iTop =
+ MM_TO_PIXEL (s->aValues[optTLY].w + s->HWParams.iTopLeftY, HW_LPI);
+ s->ScanParams.iLeft =
+ MM_TO_PIXEL (s->aValues[optTLX].w + s->HWParams.iTopLeftX, HW_DPI);
+
+ /* Note: All measurements passed to the scanning routines must be in HW_LPI */
+ s->ScanParams.iWidth =
+ MM_TO_PIXEL (s->aValues[optBRX].w - s->aValues[optTLX].w, HW_LPI);
+ s->ScanParams.iHeight =
+ MM_TO_PIXEL (s->aValues[optBRY].w - s->aValues[optTLY].w, HW_LPI);
+
+ /* After the scanning, the iLines and iBytesPerLine will be filled in */
+
+ /* copy gamma table */
+ WriteGammaCalibTable (s->HWParams.iXferHandle, s->aGammaTableR,
+ s->aGammaTableG, s->aGammaTableB);
+
+ /* prepare the actual scan */
+ /* We say normal here. In future we should have a preview flag to set preview mode */
+ if (InitScan (SCAN_TYPE_NORMAL, &s->ScanParams, &s->HWParams) != 0)
+ {
+ HP5400_DBG (DBG_MSG, "Invalid scan parameters (InitScan)\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ /* for the moment no lines has been read */
+ s->ScanParams.iLinesRead = 0;
+
+ s->fScanning = TRUE;
+ return SANE_STATUS_GOOD;
+}
+
+
+SANE_Status
+sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len)
+{
+
+ /* Read actual scan from the circular buffer */
+ /* Note: this is already color corrected, though some work still needs to be done
+ to deal with the colour offsetting */
+ TScanner *s;
+ char *buffer = (char*)buf;
+
+ HP5400_DBG (DBG_MSG, "sane_read: request %d bytes \n", maxlen);
+
+ s = (TScanner *) h;
+
+ /* nothing has been read for the moment */
+ *len = 0;
+
+
+ /* if we read all the lines return EOF */
+ if (s->ScanParams.iLinesRead == s->ScanParams.iLines)
+ {
+/* FinishScan( &s->HWParams ); *** FinishScan called in sane_cancel */
+ HP5400_DBG (DBG_MSG, "sane_read: EOF\n");
+ return SANE_STATUS_EOF;
+ }
+
+ /* read as many lines the buffer may contain and while there are lines to be read */
+ while ((*len + s->ScanParams.iBytesPerLine <= maxlen)
+ && (s->ScanParams.iLinesRead < s->ScanParams.iLines))
+ {
+
+ /* get one more line from the circular buffer */
+ CircBufferGetLine (s->HWParams.iXferHandle, &s->HWParams.pipe, buffer);
+
+ /* increment pointer, size and line number */
+ buffer += s->ScanParams.iBytesPerLine;
+ *len += s->ScanParams.iBytesPerLine;
+ s->ScanParams.iLinesRead++;
+ }
+
+ HP5400_DBG (DBG_MSG, "sane_read: %d bytes read\n", *len);
+
+ return SANE_STATUS_GOOD;
+}
+
+
+void
+sane_cancel (SANE_Handle h)
+{
+ TScanner *s;
+
+ HP5400_DBG (DBG_MSG, "sane_cancel\n");
+
+ s = (TScanner *) h;
+
+ /* to be implemented more thoroughly */
+
+ /* Make sure the scanner head returns home */
+ FinishScan (&s->HWParams);
+
+ s->fCanceled = TRUE;
+ s->fScanning = FALSE;
+}
+
+
+SANE_Status
+sane_set_io_mode (SANE_Handle h, SANE_Bool m)
+{
+ HP5400_DBG (DBG_MSG, "sane_set_io_mode %s\n", m ? "non-blocking" : "blocking");
+
+ /* prevent compiler from complaining about unused parameters */
+ h = h;
+
+ if (m)
+ {
+ return SANE_STATUS_UNSUPPORTED;
+ }
+ return SANE_STATUS_GOOD;
+}
+
+
+SANE_Status
+sane_get_select_fd (SANE_Handle h, SANE_Int * fd)
+{
+ HP5400_DBG (DBG_MSG, "sane_select_fd\n");
+
+ /* prevent compiler from complaining about unused parameters */
+ h = h;
+ fd = fd;
+
+ return SANE_STATUS_UNSUPPORTED;
+}