diff options
Diffstat (limited to 'backend/hp5400_sane.c')
-rw-r--r-- | backend/hp5400_sane.c | 1022 |
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; +} |