1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci   Copyright (C) 2020 Ralph Little <skelband@gmail.com>
3141cc406Sopenharmony_ci   Copyright (C) 2003 Martijn van Oosterhout <kleptog@svana.org>
4141cc406Sopenharmony_ci   Copyright (C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   Originally copied from HP3300 testtools. Original notice follows:
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci   Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl)
9141cc406Sopenharmony_ci
10141cc406Sopenharmony_ci   This file is part of the SANE package.
11141cc406Sopenharmony_ci
12141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
13141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License
14141cc406Sopenharmony_ci   as published by the Free Software Foundation; either version 2
15141cc406Sopenharmony_ci   of the License, or (at your option) any later version.
16141cc406Sopenharmony_ci
17141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful,
18141cc406Sopenharmony_ci   but WITHOUT ANY WARRANTY; without even the implied warranty of
19141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20141cc406Sopenharmony_ci   GNU General Public License for more details.
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
23141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
24141cc406Sopenharmony_ci
25141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
26141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
27141cc406Sopenharmony_ci
28141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
29141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
30141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
31141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
32141cc406Sopenharmony_ci   account of linking the SANE library code into it.
33141cc406Sopenharmony_ci
34141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
35141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
36141cc406Sopenharmony_ci   License.
37141cc406Sopenharmony_ci
38141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
39141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
40141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
41141cc406Sopenharmony_ci
42141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
43141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
44141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
45141cc406Sopenharmony_ci*/
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci/*
49141cc406Sopenharmony_ci    SANE interface for hp54xx scanners. Prototype.
50141cc406Sopenharmony_ci    Parts of this source were inspired by other backends.
51141cc406Sopenharmony_ci*/
52141cc406Sopenharmony_ci
53141cc406Sopenharmony_ci#include "../include/sane/config.h"
54141cc406Sopenharmony_ci
55141cc406Sopenharmony_ci/* definitions for debug */
56141cc406Sopenharmony_ci#include "hp5400_debug.h"
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci#include "../include/sane/sane.h"
59141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
60141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
61141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
62141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
63141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci#include <stdlib.h>         /* malloc, free */
66141cc406Sopenharmony_ci#include <string.h>         /* memcpy */
67141cc406Sopenharmony_ci#include <stdio.h>
68141cc406Sopenharmony_ci#include <errno.h>
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_ci#define HP5400_CONFIG_FILE "hp5400.conf"
71141cc406Sopenharmony_ci
72141cc406Sopenharmony_ci#include "hp5400.h"
73141cc406Sopenharmony_ci
74141cc406Sopenharmony_ci/* other definitions */
75141cc406Sopenharmony_ci#ifndef min
76141cc406Sopenharmony_ci#define min(A,B) (((A)<(B)) ? (A) : (B))
77141cc406Sopenharmony_ci#endif
78141cc406Sopenharmony_ci#ifndef max
79141cc406Sopenharmony_ci#define max(A,B) (((A)>(B)) ? (A) : (B))
80141cc406Sopenharmony_ci#endif
81141cc406Sopenharmony_ci
82141cc406Sopenharmony_ci#define TRUE 1
83141cc406Sopenharmony_ci#define FALSE 0
84141cc406Sopenharmony_ci
85141cc406Sopenharmony_ci#define MM_TO_PIXEL(_mm_, _dpi_)    ((_mm_) * (_dpi_) / 25.4)
86141cc406Sopenharmony_ci#define PIXEL_TO_MM(_pixel_, _dpi_) ((_pixel_) * 25.4 / (_dpi_))
87141cc406Sopenharmony_ci
88141cc406Sopenharmony_ci#define NUM_GAMMA_ENTRIES  65536
89141cc406Sopenharmony_ci
90141cc406Sopenharmony_ci
91141cc406Sopenharmony_ci/* options enumerator */
92141cc406Sopenharmony_citypedef enum
93141cc406Sopenharmony_ci{
94141cc406Sopenharmony_ci  optCount = 0,
95141cc406Sopenharmony_ci
96141cc406Sopenharmony_ci  optDPI,
97141cc406Sopenharmony_ci
98141cc406Sopenharmony_ci  optGroupGeometry,
99141cc406Sopenharmony_ci  optTLX, optTLY, optBRX, optBRY,
100141cc406Sopenharmony_ci
101141cc406Sopenharmony_ci  optGroupEnhancement,
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci  optGammaTableRed,		/* Gamma Tables */
104141cc406Sopenharmony_ci  optGammaTableGreen,
105141cc406Sopenharmony_ci  optGammaTableBlue,
106141cc406Sopenharmony_ci
107141cc406Sopenharmony_ci  optGroupSensors,
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_ci  optSensorScanTo,
110141cc406Sopenharmony_ci  optSensorWeb,
111141cc406Sopenharmony_ci  optSensorReprint,
112141cc406Sopenharmony_ci  optSensorEmail,
113141cc406Sopenharmony_ci  optSensorCopy,
114141cc406Sopenharmony_ci  optSensorMoreOptions,
115141cc406Sopenharmony_ci  optSensorCancel,
116141cc406Sopenharmony_ci  optSensorPowerSave,
117141cc406Sopenharmony_ci  optSensorCopiesUp,
118141cc406Sopenharmony_ci  optSensorCopiesDown,
119141cc406Sopenharmony_ci  optSensorColourBW,
120141cc406Sopenharmony_ci
121141cc406Sopenharmony_ci  optSensorColourBWState,
122141cc406Sopenharmony_ci  optSensorCopyCount,
123141cc406Sopenharmony_ci
124141cc406Sopenharmony_ci  // Unsupported as yet.
125141cc406Sopenharmony_ci  //optGroupMisc,
126141cc406Sopenharmony_ci  //optLamp,
127141cc406Sopenharmony_ci  //optCalibrate,
128141cc406Sopenharmony_ci
129141cc406Sopenharmony_ci  optLast,			/* Disable the offset code */
130141cc406Sopenharmony_ci}
131141cc406Sopenharmony_ciEOptionIndex;
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_ci/*
134141cc406Sopenharmony_ci * Array mapping (optSensor* - optGroupSensors - 1) to the bit mask of the
135141cc406Sopenharmony_ci * corresponding sensor bit that we get from the scanner.
136141cc406Sopenharmony_ci * All sensor bits are reported as a complete 16-bit word with individual bits set
137141cc406Sopenharmony_ci * to indicate that the sensor has been activated.
138141cc406Sopenharmony_ci * They seem to be latched so that they are picked up on next query and a number
139141cc406Sopenharmony_ci * of bits can be set in any one query.
140141cc406Sopenharmony_ci *
141141cc406Sopenharmony_ci */
142141cc406Sopenharmony_ci
143141cc406Sopenharmony_ci#define SENSOR_BIT_SCAN           0x0400
144141cc406Sopenharmony_ci#define SENSOR_BIT_WEB            0x0200
145141cc406Sopenharmony_ci#define SENSOR_BIT_REPRINT        0x0002
146141cc406Sopenharmony_ci#define SENSOR_BIT_EMAIL          0x0080
147141cc406Sopenharmony_ci#define SENSOR_BIT_COPY           0x0040
148141cc406Sopenharmony_ci#define SENSOR_BIT_MOREOPTIONS    0x0004
149141cc406Sopenharmony_ci#define SENSOR_BIT_CANCEL         0x0100
150141cc406Sopenharmony_ci#define SENSOR_BIT_POWERSAVE      0x2000
151141cc406Sopenharmony_ci#define SENSOR_BIT_COPIESUP       0x0008
152141cc406Sopenharmony_ci#define SENSOR_BIT_COPIESDOWN     0x0020
153141cc406Sopenharmony_ci#define SENSOR_BIT_COLOURBW       0x0010
154141cc406Sopenharmony_ci
155141cc406Sopenharmony_ci
156141cc406Sopenharmony_ciuint16_t sensorMaskMap[] =
157141cc406Sopenharmony_ci{
158141cc406Sopenharmony_ci    SENSOR_BIT_SCAN,
159141cc406Sopenharmony_ci    SENSOR_BIT_WEB,
160141cc406Sopenharmony_ci    SENSOR_BIT_REPRINT,
161141cc406Sopenharmony_ci    SENSOR_BIT_EMAIL,
162141cc406Sopenharmony_ci    SENSOR_BIT_COPY,
163141cc406Sopenharmony_ci    SENSOR_BIT_MOREOPTIONS,
164141cc406Sopenharmony_ci    SENSOR_BIT_CANCEL,
165141cc406Sopenharmony_ci
166141cc406Sopenharmony_ci    // Special buttons.
167141cc406Sopenharmony_ci    // These affect local machine settings, but we can still detect them being pressed.
168141cc406Sopenharmony_ci    SENSOR_BIT_POWERSAVE,
169141cc406Sopenharmony_ci    SENSOR_BIT_COPIESUP,
170141cc406Sopenharmony_ci    SENSOR_BIT_COPIESDOWN,
171141cc406Sopenharmony_ci    SENSOR_BIT_COLOURBW,
172141cc406Sopenharmony_ci
173141cc406Sopenharmony_ci    // Extra entries to make the array up to the 16 possible bits.
174141cc406Sopenharmony_ci    0x0000,     // Unused
175141cc406Sopenharmony_ci    0x0000,     // Unused
176141cc406Sopenharmony_ci    0x0000,     // Unused
177141cc406Sopenharmony_ci    0x0000,     // Unused
178141cc406Sopenharmony_ci    0x0000      // Unused
179141cc406Sopenharmony_ci};
180141cc406Sopenharmony_ci
181141cc406Sopenharmony_citypedef union
182141cc406Sopenharmony_ci{
183141cc406Sopenharmony_ci  SANE_Word w;
184141cc406Sopenharmony_ci  SANE_Word *wa;		/* word array */
185141cc406Sopenharmony_ci  SANE_String s;
186141cc406Sopenharmony_ci}
187141cc406Sopenharmony_ciTOptionValue;
188141cc406Sopenharmony_ci
189141cc406Sopenharmony_ci
190141cc406Sopenharmony_citypedef struct
191141cc406Sopenharmony_ci{
192141cc406Sopenharmony_ci  SANE_Option_Descriptor aOptions[optLast];
193141cc406Sopenharmony_ci  TOptionValue aValues[optLast];
194141cc406Sopenharmony_ci
195141cc406Sopenharmony_ci  TScanParams ScanParams;
196141cc406Sopenharmony_ci  THWParams HWParams;
197141cc406Sopenharmony_ci
198141cc406Sopenharmony_ci  TDataPipe DataPipe;
199141cc406Sopenharmony_ci  int iLinesLeft;
200141cc406Sopenharmony_ci
201141cc406Sopenharmony_ci  SANE_Int *aGammaTableR;	/* a 16-to-16 bit color lookup table */
202141cc406Sopenharmony_ci  SANE_Int *aGammaTableG;	/* a 16-to-16 bit color lookup table */
203141cc406Sopenharmony_ci  SANE_Int *aGammaTableB;	/* a 16-to-16 bit color lookup table */
204141cc406Sopenharmony_ci
205141cc406Sopenharmony_ci  int fScanning;		/* TRUE if actively scanning */
206141cc406Sopenharmony_ci  int fCanceled;
207141cc406Sopenharmony_ci
208141cc406Sopenharmony_ci  uint16_t sensorMap;           /* Contains the current unreported sensor bits. */
209141cc406Sopenharmony_ci}
210141cc406Sopenharmony_ciTScanner;
211141cc406Sopenharmony_ci
212141cc406Sopenharmony_ci
213141cc406Sopenharmony_ci/* linked list of SANE_Device structures */
214141cc406Sopenharmony_citypedef struct TDevListEntry
215141cc406Sopenharmony_ci{
216141cc406Sopenharmony_ci  struct TDevListEntry *pNext;
217141cc406Sopenharmony_ci  SANE_Device dev;
218141cc406Sopenharmony_ci  char* devname;
219141cc406Sopenharmony_ci}
220141cc406Sopenharmony_ciTDevListEntry;
221141cc406Sopenharmony_ci
222141cc406Sopenharmony_ci
223141cc406Sopenharmony_ci
224141cc406Sopenharmony_ci/* Device filename for USB access */
225141cc406Sopenharmony_cichar usb_devfile[128];
226141cc406Sopenharmony_ci
227141cc406Sopenharmony_cistatic TDevListEntry *_pFirstSaneDev = 0;
228141cc406Sopenharmony_cistatic int iNumSaneDev = 0;
229141cc406Sopenharmony_ci
230141cc406Sopenharmony_ci
231141cc406Sopenharmony_cistatic const SANE_Device **_pSaneDevList = 0;
232141cc406Sopenharmony_ci
233141cc406Sopenharmony_ci/* option constraints */
234141cc406Sopenharmony_cistatic const SANE_Range rangeGammaTable = {0, 65535, 1};
235141cc406Sopenharmony_cistatic const SANE_Range rangeCopyCountTable = {0, 99, 1};
236141cc406Sopenharmony_cistatic SANE_String_Const modeSwitchList[] = {
237141cc406Sopenharmony_ci    SANE_VALUE_SCAN_MODE_COLOR,
238141cc406Sopenharmony_ci    SANE_VALUE_SCAN_MODE_GRAY,
239141cc406Sopenharmony_ci    NULL
240141cc406Sopenharmony_ci};
241141cc406Sopenharmony_ci#ifdef SUPPORT_2400_DPI
242141cc406Sopenharmony_cistatic const SANE_Int   setResolutions[] = {6, 75, 150, 300, 600, 1200, 2400};
243141cc406Sopenharmony_ci#else
244141cc406Sopenharmony_cistatic const SANE_Int   setResolutions[] = {5, 75, 150, 300, 600, 1200};
245141cc406Sopenharmony_ci#endif
246141cc406Sopenharmony_cistatic const SANE_Range rangeXmm = {0, 216, 1};
247141cc406Sopenharmony_cistatic const SANE_Range rangeYmm = {0, 297, 1};
248141cc406Sopenharmony_ci
249141cc406Sopenharmony_cistatic void _InitOptions(TScanner *s)
250141cc406Sopenharmony_ci{
251141cc406Sopenharmony_ci  int i, j;
252141cc406Sopenharmony_ci  SANE_Option_Descriptor *pDesc;
253141cc406Sopenharmony_ci  TOptionValue *pVal;
254141cc406Sopenharmony_ci
255141cc406Sopenharmony_ci  /* set a neutral gamma */
256141cc406Sopenharmony_ci  if( s->aGammaTableR == NULL )   /* Not yet allocated */
257141cc406Sopenharmony_ci  {
258141cc406Sopenharmony_ci    s->aGammaTableR = malloc( NUM_GAMMA_ENTRIES * sizeof( SANE_Int ) );
259141cc406Sopenharmony_ci    s->aGammaTableG = malloc( NUM_GAMMA_ENTRIES * sizeof( SANE_Int ) );
260141cc406Sopenharmony_ci    s->aGammaTableB = malloc( NUM_GAMMA_ENTRIES * sizeof( SANE_Int ) );
261141cc406Sopenharmony_ci
262141cc406Sopenharmony_ci    for (j = 0; j < NUM_GAMMA_ENTRIES; j++) {
263141cc406Sopenharmony_ci      s->aGammaTableR[j] = j;
264141cc406Sopenharmony_ci      s->aGammaTableG[j] = j;
265141cc406Sopenharmony_ci      s->aGammaTableB[j] = j;
266141cc406Sopenharmony_ci    }
267141cc406Sopenharmony_ci  }
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci  for (i = optCount; i < optLast; i++) {
270141cc406Sopenharmony_ci
271141cc406Sopenharmony_ci    pDesc = &s->aOptions[i];
272141cc406Sopenharmony_ci    pVal = &s->aValues[i];
273141cc406Sopenharmony_ci
274141cc406Sopenharmony_ci    /* defaults */
275141cc406Sopenharmony_ci    pDesc->name   = "";
276141cc406Sopenharmony_ci    pDesc->title  = "";
277141cc406Sopenharmony_ci    pDesc->desc   = "";
278141cc406Sopenharmony_ci    pDesc->type   = SANE_TYPE_INT;
279141cc406Sopenharmony_ci    pDesc->unit   = SANE_UNIT_NONE;
280141cc406Sopenharmony_ci    pDesc->size   = sizeof(SANE_Word);
281141cc406Sopenharmony_ci    pDesc->constraint_type = SANE_CONSTRAINT_NONE;
282141cc406Sopenharmony_ci    pDesc->cap    = 0;
283141cc406Sopenharmony_ci
284141cc406Sopenharmony_ci    switch (i) {
285141cc406Sopenharmony_ci
286141cc406Sopenharmony_ci    case optCount:
287141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_NUM_OPTIONS;
288141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_NUM_OPTIONS;
289141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT;
290141cc406Sopenharmony_ci      pVal->w       = (SANE_Word)optLast;
291141cc406Sopenharmony_ci      break;
292141cc406Sopenharmony_ci
293141cc406Sopenharmony_ci    case optDPI:
294141cc406Sopenharmony_ci      pDesc->name   = SANE_NAME_SCAN_RESOLUTION;
295141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_SCAN_RESOLUTION;
296141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_SCAN_RESOLUTION;
297141cc406Sopenharmony_ci      pDesc->unit   = SANE_UNIT_DPI;
298141cc406Sopenharmony_ci      pDesc->constraint_type  = SANE_CONSTRAINT_WORD_LIST;
299141cc406Sopenharmony_ci      pDesc->constraint.word_list = setResolutions;
300141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
301141cc406Sopenharmony_ci      pVal->w       = setResolutions[1];
302141cc406Sopenharmony_ci      break;
303141cc406Sopenharmony_ci
304141cc406Sopenharmony_ci      //---------------------------------
305141cc406Sopenharmony_ci    case optGroupGeometry:
306141cc406Sopenharmony_ci      pDesc->name  = SANE_NAME_GEOMETRY;
307141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_GEOMETRY;
308141cc406Sopenharmony_ci      pDesc->desc  = SANE_DESC_GEOMETRY;
309141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_GROUP;
310141cc406Sopenharmony_ci      pDesc->size   = 0;
311141cc406Sopenharmony_ci      break;
312141cc406Sopenharmony_ci
313141cc406Sopenharmony_ci    case optTLX:
314141cc406Sopenharmony_ci      pDesc->name   = SANE_NAME_SCAN_TL_X;
315141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_SCAN_TL_X;
316141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_SCAN_TL_X;
317141cc406Sopenharmony_ci      pDesc->unit   = SANE_UNIT_MM;
318141cc406Sopenharmony_ci      pDesc->constraint_type  = SANE_CONSTRAINT_RANGE;
319141cc406Sopenharmony_ci      pDesc->constraint.range = &rangeXmm;
320141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
321141cc406Sopenharmony_ci      pVal->w       = rangeXmm.min;
322141cc406Sopenharmony_ci      break;
323141cc406Sopenharmony_ci
324141cc406Sopenharmony_ci    case optTLY:
325141cc406Sopenharmony_ci      pDesc->name   = SANE_NAME_SCAN_TL_Y;
326141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_SCAN_TL_Y;
327141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_SCAN_TL_Y;
328141cc406Sopenharmony_ci      pDesc->unit   = SANE_UNIT_MM;
329141cc406Sopenharmony_ci      pDesc->constraint_type  = SANE_CONSTRAINT_RANGE;
330141cc406Sopenharmony_ci      pDesc->constraint.range = &rangeYmm;
331141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
332141cc406Sopenharmony_ci      pVal->w       = rangeYmm.min;
333141cc406Sopenharmony_ci      break;
334141cc406Sopenharmony_ci
335141cc406Sopenharmony_ci    case optBRX:
336141cc406Sopenharmony_ci      pDesc->name   = SANE_NAME_SCAN_BR_X;
337141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_SCAN_BR_X;
338141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_SCAN_BR_X;
339141cc406Sopenharmony_ci      pDesc->unit   = SANE_UNIT_MM;
340141cc406Sopenharmony_ci      pDesc->constraint_type  = SANE_CONSTRAINT_RANGE;
341141cc406Sopenharmony_ci      pDesc->constraint.range = &rangeXmm;
342141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
343141cc406Sopenharmony_ci      pVal->w       = rangeXmm.max;
344141cc406Sopenharmony_ci      break;
345141cc406Sopenharmony_ci
346141cc406Sopenharmony_ci    case optBRY:
347141cc406Sopenharmony_ci      pDesc->name   = SANE_NAME_SCAN_BR_Y;
348141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_SCAN_BR_Y;
349141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_SCAN_BR_Y;
350141cc406Sopenharmony_ci      pDesc->unit   = SANE_UNIT_MM;
351141cc406Sopenharmony_ci      pDesc->constraint_type  = SANE_CONSTRAINT_RANGE;
352141cc406Sopenharmony_ci      pDesc->constraint.range = &rangeYmm;
353141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
354141cc406Sopenharmony_ci      pVal->w       = rangeYmm.max;
355141cc406Sopenharmony_ci      break;
356141cc406Sopenharmony_ci
357141cc406Sopenharmony_ci      //---------------------------------
358141cc406Sopenharmony_ci    case optGroupEnhancement:
359141cc406Sopenharmony_ci      pDesc->name  = SANE_NAME_ENHANCEMENT;
360141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_ENHANCEMENT;
361141cc406Sopenharmony_ci      pDesc->desc  = SANE_DESC_ENHANCEMENT;
362141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_GROUP;
363141cc406Sopenharmony_ci      pDesc->size   = 0;
364141cc406Sopenharmony_ci      break;
365141cc406Sopenharmony_ci
366141cc406Sopenharmony_ci    case optGammaTableRed:
367141cc406Sopenharmony_ci      pDesc->name   = SANE_NAME_GAMMA_VECTOR_R;
368141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_GAMMA_VECTOR_R;
369141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_GAMMA_VECTOR_R;
370141cc406Sopenharmony_ci      pDesc->size   = NUM_GAMMA_ENTRIES * sizeof( SANE_Int );
371141cc406Sopenharmony_ci      pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
372141cc406Sopenharmony_ci      pDesc->constraint.range = &rangeGammaTable;
373141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
374141cc406Sopenharmony_ci      pVal->wa      = s->aGammaTableR;
375141cc406Sopenharmony_ci      break;
376141cc406Sopenharmony_ci
377141cc406Sopenharmony_ci    case optGammaTableGreen:
378141cc406Sopenharmony_ci      pDesc->name   = SANE_NAME_GAMMA_VECTOR_G;
379141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_GAMMA_VECTOR_G;
380141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_GAMMA_VECTOR_G;
381141cc406Sopenharmony_ci      pDesc->size   = NUM_GAMMA_ENTRIES * sizeof( SANE_Int );
382141cc406Sopenharmony_ci      pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
383141cc406Sopenharmony_ci      pDesc->constraint.range = &rangeGammaTable;
384141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
385141cc406Sopenharmony_ci      pVal->wa      = s->aGammaTableG;
386141cc406Sopenharmony_ci      break;
387141cc406Sopenharmony_ci
388141cc406Sopenharmony_ci    case optGammaTableBlue:
389141cc406Sopenharmony_ci      pDesc->name   = SANE_NAME_GAMMA_VECTOR_B;
390141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_GAMMA_VECTOR_B;
391141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_GAMMA_VECTOR_B;
392141cc406Sopenharmony_ci      pDesc->size   = NUM_GAMMA_ENTRIES * sizeof( SANE_Int );
393141cc406Sopenharmony_ci      pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
394141cc406Sopenharmony_ci      pDesc->constraint.range = &rangeGammaTable;
395141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
396141cc406Sopenharmony_ci      pVal->wa      = s->aGammaTableB;
397141cc406Sopenharmony_ci      break;
398141cc406Sopenharmony_ci
399141cc406Sopenharmony_ci      //---------------------------------
400141cc406Sopenharmony_ci    case optGroupSensors:
401141cc406Sopenharmony_ci      pDesc->name  = SANE_NAME_SENSORS;
402141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_SENSORS;
403141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_GROUP;
404141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_SENSORS;
405141cc406Sopenharmony_ci      pDesc->size   = 0;
406141cc406Sopenharmony_ci      break;
407141cc406Sopenharmony_ci
408141cc406Sopenharmony_ci    case optSensorScanTo:
409141cc406Sopenharmony_ci      pDesc->name   = SANE_NAME_SCAN;
410141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_SCAN;
411141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_SCAN;
412141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BOOL;
413141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
414141cc406Sopenharmony_ci      break;
415141cc406Sopenharmony_ci
416141cc406Sopenharmony_ci    case optSensorWeb:
417141cc406Sopenharmony_ci      pDesc->name   = SANE_I18N("web");
418141cc406Sopenharmony_ci      pDesc->title  = SANE_I18N("Share-To-Web button");
419141cc406Sopenharmony_ci      pDesc->desc   = SANE_I18N("Scan an image and send it on the web");
420141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BOOL;
421141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
422141cc406Sopenharmony_ci      break;
423141cc406Sopenharmony_ci
424141cc406Sopenharmony_ci    case optSensorReprint:
425141cc406Sopenharmony_ci      pDesc->name   = SANE_I18N("reprint");
426141cc406Sopenharmony_ci      pDesc->title  = SANE_I18N("Reprint Photos button");
427141cc406Sopenharmony_ci      pDesc->desc   = SANE_I18N("Button for reprinting photos");
428141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BOOL;
429141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
430141cc406Sopenharmony_ci      break;
431141cc406Sopenharmony_ci
432141cc406Sopenharmony_ci    case optSensorEmail:
433141cc406Sopenharmony_ci      pDesc->name   = SANE_NAME_EMAIL;
434141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_EMAIL;
435141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_EMAIL;
436141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BOOL;
437141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
438141cc406Sopenharmony_ci      break;
439141cc406Sopenharmony_ci
440141cc406Sopenharmony_ci    case optSensorCopy:
441141cc406Sopenharmony_ci      pDesc->name   = SANE_NAME_COPY;
442141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_COPY;
443141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_COPY;
444141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BOOL;
445141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
446141cc406Sopenharmony_ci      break;
447141cc406Sopenharmony_ci
448141cc406Sopenharmony_ci    case optSensorMoreOptions:
449141cc406Sopenharmony_ci      pDesc->name   = SANE_I18N("more-options");
450141cc406Sopenharmony_ci      pDesc->title  = SANE_I18N("More Options button");
451141cc406Sopenharmony_ci      pDesc->desc   = SANE_I18N("Button for additional options/configuration");
452141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BOOL;
453141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
454141cc406Sopenharmony_ci      break;
455141cc406Sopenharmony_ci
456141cc406Sopenharmony_ci    case optSensorCancel:
457141cc406Sopenharmony_ci      pDesc->name   = SANE_NAME_CANCEL;
458141cc406Sopenharmony_ci      pDesc->title  = SANE_TITLE_CANCEL;
459141cc406Sopenharmony_ci      pDesc->desc   = SANE_DESC_CANCEL;
460141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BOOL;
461141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
462141cc406Sopenharmony_ci      break;
463141cc406Sopenharmony_ci
464141cc406Sopenharmony_ci    case optSensorPowerSave:
465141cc406Sopenharmony_ci      pDesc->name   = SANE_I18N("power-save");
466141cc406Sopenharmony_ci      pDesc->title  = SANE_I18N("Power Save button");
467141cc406Sopenharmony_ci      pDesc->desc   = SANE_I18N("Puts the scanner in an energy-conservation mode");
468141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BOOL;
469141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
470141cc406Sopenharmony_ci      break;
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci    case optSensorCopiesUp:
473141cc406Sopenharmony_ci      pDesc->name   = SANE_I18N("copies-up");
474141cc406Sopenharmony_ci      pDesc->title  = SANE_I18N("Increase Copies button");
475141cc406Sopenharmony_ci      pDesc->desc   = SANE_I18N("Increase the number of copies");
476141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BOOL;
477141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
478141cc406Sopenharmony_ci      break;
479141cc406Sopenharmony_ci
480141cc406Sopenharmony_ci    case optSensorCopiesDown:
481141cc406Sopenharmony_ci      pDesc->name   = SANE_I18N("copies-down");
482141cc406Sopenharmony_ci      pDesc->title  = SANE_I18N("Decrease Copies button");
483141cc406Sopenharmony_ci      pDesc->desc   = SANE_I18N("Decrease the number of copies");
484141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BOOL;
485141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
486141cc406Sopenharmony_ci      break;
487141cc406Sopenharmony_ci
488141cc406Sopenharmony_ci    case optSensorColourBW:
489141cc406Sopenharmony_ci      pDesc->name   = SANE_I18N("color-bw");
490141cc406Sopenharmony_ci      pDesc->title  = SANE_I18N("Select color/BW button");
491141cc406Sopenharmony_ci      pDesc->desc   = SANE_I18N("Alternates between color and black/white scanning");
492141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BOOL;
493141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
494141cc406Sopenharmony_ci      break;
495141cc406Sopenharmony_ci
496141cc406Sopenharmony_ci    case optSensorColourBWState:
497141cc406Sopenharmony_ci      pDesc->name   = SANE_I18N("color-bw-state");
498141cc406Sopenharmony_ci      pDesc->title  = SANE_I18N("Read color/BW button state");
499141cc406Sopenharmony_ci      pDesc->desc   = SANE_I18N("Reads state of BW/colour panel setting");
500141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_STRING;
501141cc406Sopenharmony_ci      pDesc->constraint_type  = SANE_CONSTRAINT_STRING_LIST;
502141cc406Sopenharmony_ci      pDesc->constraint.string_list = modeSwitchList;
503141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED;
504141cc406Sopenharmony_ci      break;
505141cc406Sopenharmony_ci
506141cc406Sopenharmony_ci    case optSensorCopyCount:
507141cc406Sopenharmony_ci      pDesc->name   = SANE_I18N("copies-count");
508141cc406Sopenharmony_ci      pDesc->title  = SANE_I18N("Read copy count value");
509141cc406Sopenharmony_ci      pDesc->desc   = SANE_I18N("Reads state of copy count panel setting");
510141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_INT;
511141cc406Sopenharmony_ci      pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
512141cc406Sopenharmony_ci      pDesc->constraint.range = &rangeCopyCountTable;
513141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED;
514141cc406Sopenharmony_ci      break;
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci#if 0
517141cc406Sopenharmony_ci    case optGroupMisc:
518141cc406Sopenharmony_ci      pDesc->title  = SANE_I18N("Miscellaneous");
519141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_GROUP;
520141cc406Sopenharmony_ci      pDesc->size   = 0;
521141cc406Sopenharmony_ci      break;
522141cc406Sopenharmony_ci
523141cc406Sopenharmony_ci    case optLamp:
524141cc406Sopenharmony_ci      pDesc->name   = "lamp";
525141cc406Sopenharmony_ci      pDesc->title  = SANE_I18N("Lamp status");
526141cc406Sopenharmony_ci      pDesc->desc   = SANE_I18N("Switches the lamp on or off.");
527141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BOOL;
528141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
529141cc406Sopenharmony_ci      /* switch the lamp on when starting for first the time */
530141cc406Sopenharmony_ci      pVal->w       = SANE_TRUE;
531141cc406Sopenharmony_ci      break;
532141cc406Sopenharmony_ci
533141cc406Sopenharmony_ci    case optCalibrate:
534141cc406Sopenharmony_ci      pDesc->name   = "calibrate";
535141cc406Sopenharmony_ci      pDesc->title  = SANE_I18N("Calibrate");
536141cc406Sopenharmony_ci      pDesc->desc   = SANE_I18N("Calibrates for black and white level.");
537141cc406Sopenharmony_ci      pDesc->type   = SANE_TYPE_BUTTON;
538141cc406Sopenharmony_ci      pDesc->cap    = SANE_CAP_SOFT_SELECT;
539141cc406Sopenharmony_ci      pDesc->size   = 0;
540141cc406Sopenharmony_ci      break;
541141cc406Sopenharmony_ci#endif
542141cc406Sopenharmony_ci    default:
543141cc406Sopenharmony_ci      HP5400_DBG(DBG_ERR, "Uninitialised option %d\n", i);
544141cc406Sopenharmony_ci      break;
545141cc406Sopenharmony_ci    }
546141cc406Sopenharmony_ci  }
547141cc406Sopenharmony_ci}
548141cc406Sopenharmony_ci
549141cc406Sopenharmony_ci
550141cc406Sopenharmony_cistatic int _ReportDevice(TScannerModel *pModel, const char *pszDeviceName)
551141cc406Sopenharmony_ci{
552141cc406Sopenharmony_ci  TDevListEntry *pNew, *pDev;
553141cc406Sopenharmony_ci
554141cc406Sopenharmony_ci  HP5400_DBG(DBG_MSG, "hp5400: _ReportDevice '%s'\n", pszDeviceName);
555141cc406Sopenharmony_ci
556141cc406Sopenharmony_ci  pNew = malloc(sizeof(TDevListEntry));
557141cc406Sopenharmony_ci  if (!pNew) {
558141cc406Sopenharmony_ci    HP5400_DBG(DBG_ERR, "no mem\n");
559141cc406Sopenharmony_ci    return -1;
560141cc406Sopenharmony_ci  }
561141cc406Sopenharmony_ci
562141cc406Sopenharmony_ci  /* add new element to the end of the list */
563141cc406Sopenharmony_ci  if (_pFirstSaneDev == NULL) {
564141cc406Sopenharmony_ci    _pFirstSaneDev = pNew;
565141cc406Sopenharmony_ci  }
566141cc406Sopenharmony_ci  else {
567141cc406Sopenharmony_ci    for (pDev = _pFirstSaneDev; pDev->pNext; pDev = pDev->pNext) {
568141cc406Sopenharmony_ci      ;
569141cc406Sopenharmony_ci    }
570141cc406Sopenharmony_ci    pDev->pNext = pNew;
571141cc406Sopenharmony_ci  }
572141cc406Sopenharmony_ci
573141cc406Sopenharmony_ci  /* fill in new element */
574141cc406Sopenharmony_ci  pNew->pNext = 0;
575141cc406Sopenharmony_ci  /* we use devname to avoid having to free a const
576141cc406Sopenharmony_ci   * pointer */
577141cc406Sopenharmony_ci  pNew->devname = (char*)strdup(pszDeviceName);
578141cc406Sopenharmony_ci  pNew->dev.name = pNew->devname;
579141cc406Sopenharmony_ci  pNew->dev.vendor = pModel->pszVendor;
580141cc406Sopenharmony_ci  pNew->dev.model = pModel->pszName;
581141cc406Sopenharmony_ci  pNew->dev.type = "flatbed scanner";
582141cc406Sopenharmony_ci
583141cc406Sopenharmony_ci  iNumSaneDev++;
584141cc406Sopenharmony_ci
585141cc406Sopenharmony_ci  return 0;
586141cc406Sopenharmony_ci}
587141cc406Sopenharmony_ci
588141cc406Sopenharmony_cistatic SANE_Status
589141cc406Sopenharmony_ciattach_one_device (SANE_String_Const devname)
590141cc406Sopenharmony_ci{
591141cc406Sopenharmony_ci  const char * filename = (const char*) devname;
592141cc406Sopenharmony_ci  if (HP5400Detect (filename, _ReportDevice) < 0)
593141cc406Sopenharmony_ci    {
594141cc406Sopenharmony_ci      HP5400_DBG (DBG_MSG, "attach_one_device: couldn't attach %s\n", devname);
595141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
596141cc406Sopenharmony_ci    }
597141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "attach_one_device: attached %s successfully\n", devname);
598141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
599141cc406Sopenharmony_ci}
600141cc406Sopenharmony_ci
601141cc406Sopenharmony_ci
602141cc406Sopenharmony_ci/*****************************************************************************/
603141cc406Sopenharmony_ci
604141cc406Sopenharmony_ciSANE_Status
605141cc406Sopenharmony_cisane_init (SANE_Int * piVersion, SANE_Auth_Callback pfnAuth)
606141cc406Sopenharmony_ci{
607141cc406Sopenharmony_ci  FILE *conf_fp;		/* Config file stream  */
608141cc406Sopenharmony_ci  SANE_Char line[PATH_MAX];
609141cc406Sopenharmony_ci  SANE_Char *str = NULL;
610141cc406Sopenharmony_ci  SANE_String_Const proper_str;
611141cc406Sopenharmony_ci  int nline = 0;
612141cc406Sopenharmony_ci
613141cc406Sopenharmony_ci  /* prevent compiler from complaining about unused parameters */
614141cc406Sopenharmony_ci  (void) pfnAuth;
615141cc406Sopenharmony_ci
616141cc406Sopenharmony_ci  strcpy(usb_devfile, "/dev/usb/scanner0");
617141cc406Sopenharmony_ci  _pFirstSaneDev = 0;
618141cc406Sopenharmony_ci  iNumSaneDev = 0;
619141cc406Sopenharmony_ci
620141cc406Sopenharmony_ci  InitHp5400_internal();
621141cc406Sopenharmony_ci
622141cc406Sopenharmony_ci
623141cc406Sopenharmony_ci  DBG_INIT ();
624141cc406Sopenharmony_ci
625141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_init: SANE hp5400 backend version %d.%d-%d (from %s)\n",
626141cc406Sopenharmony_ci       SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD, PACKAGE_STRING);
627141cc406Sopenharmony_ci
628141cc406Sopenharmony_ci  sanei_usb_init ();
629141cc406Sopenharmony_ci
630141cc406Sopenharmony_ci  conf_fp = sanei_config_open (HP5400_CONFIG_FILE);
631141cc406Sopenharmony_ci
632141cc406Sopenharmony_ci  iNumSaneDev = 0;
633141cc406Sopenharmony_ci
634141cc406Sopenharmony_ci  if (conf_fp)
635141cc406Sopenharmony_ci    {
636141cc406Sopenharmony_ci      HP5400_DBG (DBG_MSG, "Reading config file\n");
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci      while (sanei_config_read (line, sizeof (line), conf_fp))
639141cc406Sopenharmony_ci	{
640141cc406Sopenharmony_ci	  ++nline;
641141cc406Sopenharmony_ci
642141cc406Sopenharmony_ci	  if (str)
643141cc406Sopenharmony_ci	    {
644141cc406Sopenharmony_ci	      free (str);
645141cc406Sopenharmony_ci	    }
646141cc406Sopenharmony_ci
647141cc406Sopenharmony_ci	  proper_str = sanei_config_get_string (line, &str);
648141cc406Sopenharmony_ci
649141cc406Sopenharmony_ci	  /* Discards white lines and comments */
650141cc406Sopenharmony_ci	  if (!str || proper_str == line || str[0] == '#')
651141cc406Sopenharmony_ci	    {
652141cc406Sopenharmony_ci	      HP5400_DBG (DBG_MSG, "Discarding line %d\n", nline);
653141cc406Sopenharmony_ci	    }
654141cc406Sopenharmony_ci	  else
655141cc406Sopenharmony_ci	    {
656141cc406Sopenharmony_ci	      /* If line's not blank or a comment, then it's the device
657141cc406Sopenharmony_ci	       * filename or a usb directive. */
658141cc406Sopenharmony_ci	      HP5400_DBG (DBG_MSG, "Trying to attach %s\n", line);
659141cc406Sopenharmony_ci	      sanei_usb_attach_matching_devices (line, attach_one_device);
660141cc406Sopenharmony_ci	    }
661141cc406Sopenharmony_ci	}			/* while */
662141cc406Sopenharmony_ci      fclose (conf_fp);
663141cc406Sopenharmony_ci    }
664141cc406Sopenharmony_ci  else
665141cc406Sopenharmony_ci    {
666141cc406Sopenharmony_ci      HP5400_DBG (DBG_ERR, "Unable to read config file \"%s\": %s\n",
667141cc406Sopenharmony_ci	   HP5400_CONFIG_FILE, strerror (errno));
668141cc406Sopenharmony_ci      HP5400_DBG (DBG_MSG, "Using default built-in values\n");
669141cc406Sopenharmony_ci      attach_one_device (usb_devfile);
670141cc406Sopenharmony_ci    }
671141cc406Sopenharmony_ci
672141cc406Sopenharmony_ci  if (piVersion != NULL)
673141cc406Sopenharmony_ci    {
674141cc406Sopenharmony_ci      *piVersion = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
675141cc406Sopenharmony_ci    }
676141cc406Sopenharmony_ci
677141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
678141cc406Sopenharmony_ci}
679141cc406Sopenharmony_ci
680141cc406Sopenharmony_ci
681141cc406Sopenharmony_civoid
682141cc406Sopenharmony_cisane_exit (void)
683141cc406Sopenharmony_ci{
684141cc406Sopenharmony_ci  TDevListEntry *pDev, *pNext;
685141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_exit\n");
686141cc406Sopenharmony_ci
687141cc406Sopenharmony_ci  /* free device list memory */
688141cc406Sopenharmony_ci  if (_pSaneDevList)
689141cc406Sopenharmony_ci    {
690141cc406Sopenharmony_ci      for (pDev = _pFirstSaneDev; pDev; pDev = pNext)
691141cc406Sopenharmony_ci	{
692141cc406Sopenharmony_ci	  pNext = pDev->pNext;
693141cc406Sopenharmony_ci	  free (pDev->devname);
694141cc406Sopenharmony_ci	  /* pDev->dev.name is the same pointer that pDev->devname */
695141cc406Sopenharmony_ci	  free (pDev);
696141cc406Sopenharmony_ci	}
697141cc406Sopenharmony_ci      _pFirstSaneDev = 0;
698141cc406Sopenharmony_ci      free (_pSaneDevList);
699141cc406Sopenharmony_ci      _pSaneDevList = 0;
700141cc406Sopenharmony_ci    }
701141cc406Sopenharmony_ci
702141cc406Sopenharmony_ci
703141cc406Sopenharmony_ci	FreeHp5400_internal();
704141cc406Sopenharmony_ci}
705141cc406Sopenharmony_ci
706141cc406Sopenharmony_ci
707141cc406Sopenharmony_ciSANE_Status
708141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
709141cc406Sopenharmony_ci{
710141cc406Sopenharmony_ci  TDevListEntry *pDev;
711141cc406Sopenharmony_ci  int i;
712141cc406Sopenharmony_ci
713141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_get_devices\n");
714141cc406Sopenharmony_ci
715141cc406Sopenharmony_ci  (void) local_only;
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci  if (_pSaneDevList)
718141cc406Sopenharmony_ci    {
719141cc406Sopenharmony_ci      free (_pSaneDevList);
720141cc406Sopenharmony_ci    }
721141cc406Sopenharmony_ci
722141cc406Sopenharmony_ci  _pSaneDevList = malloc (sizeof (*_pSaneDevList) * (iNumSaneDev + 1));
723141cc406Sopenharmony_ci  if (!_pSaneDevList)
724141cc406Sopenharmony_ci    {
725141cc406Sopenharmony_ci      HP5400_DBG (DBG_MSG, "no mem\n");
726141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
727141cc406Sopenharmony_ci    }
728141cc406Sopenharmony_ci  i = 0;
729141cc406Sopenharmony_ci  for (pDev = _pFirstSaneDev; pDev; pDev = pDev->pNext)
730141cc406Sopenharmony_ci    {
731141cc406Sopenharmony_ci      _pSaneDevList[i++] = &pDev->dev;
732141cc406Sopenharmony_ci    }
733141cc406Sopenharmony_ci  _pSaneDevList[i++] = 0;	/* last entry is 0 */
734141cc406Sopenharmony_ci
735141cc406Sopenharmony_ci  *device_list = _pSaneDevList;
736141cc406Sopenharmony_ci
737141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
738141cc406Sopenharmony_ci}
739141cc406Sopenharmony_ci
740141cc406Sopenharmony_ci
741141cc406Sopenharmony_ciSANE_Status
742141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle * h)
743141cc406Sopenharmony_ci{
744141cc406Sopenharmony_ci  TScanner *s;
745141cc406Sopenharmony_ci
746141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_open: %s\n", name);
747141cc406Sopenharmony_ci
748141cc406Sopenharmony_ci  /* check the name */
749141cc406Sopenharmony_ci  if (strlen (name) == 0)
750141cc406Sopenharmony_ci    {
751141cc406Sopenharmony_ci      /* default to first available device */
752141cc406Sopenharmony_ci      name = _pFirstSaneDev->dev.name;
753141cc406Sopenharmony_ci    }
754141cc406Sopenharmony_ci
755141cc406Sopenharmony_ci  s = malloc (sizeof (TScanner));
756141cc406Sopenharmony_ci  if (!s)
757141cc406Sopenharmony_ci    {
758141cc406Sopenharmony_ci      HP5400_DBG (DBG_MSG, "malloc failed\n");
759141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
760141cc406Sopenharmony_ci    }
761141cc406Sopenharmony_ci
762141cc406Sopenharmony_ci  memset (s, 0, sizeof (TScanner));	/* Clear everything to zero */
763141cc406Sopenharmony_ci  if (HP5400Open (&s->HWParams, name) < 0)
764141cc406Sopenharmony_ci    {
765141cc406Sopenharmony_ci      /* is this OK ? */
766141cc406Sopenharmony_ci      HP5400_DBG (DBG_ERR, "HP5400Open failed\n");
767141cc406Sopenharmony_ci      free ((void *) s);
768141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;	/* is this OK? */
769141cc406Sopenharmony_ci    }
770141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "Handle=%d\n", s->HWParams.iXferHandle);
771141cc406Sopenharmony_ci  _InitOptions (s);
772141cc406Sopenharmony_ci  *h = s;
773141cc406Sopenharmony_ci
774141cc406Sopenharmony_ci  /* Turn on lamp by default at startup */
775141cc406Sopenharmony_ci/*  SetLamp(&s->HWParams, TRUE);  */
776141cc406Sopenharmony_ci
777141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
778141cc406Sopenharmony_ci}
779141cc406Sopenharmony_ci
780141cc406Sopenharmony_ci
781141cc406Sopenharmony_civoid
782141cc406Sopenharmony_cisane_close (SANE_Handle h)
783141cc406Sopenharmony_ci{
784141cc406Sopenharmony_ci  TScanner *s;
785141cc406Sopenharmony_ci
786141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_close\n");
787141cc406Sopenharmony_ci
788141cc406Sopenharmony_ci  s = (TScanner *) h;
789141cc406Sopenharmony_ci
790141cc406Sopenharmony_ci  /* turn of scanner lamp */
791141cc406Sopenharmony_ci  SetLamp (&s->HWParams, FALSE);
792141cc406Sopenharmony_ci
793141cc406Sopenharmony_ci  /* close scanner */
794141cc406Sopenharmony_ci  HP5400Close (&s->HWParams);
795141cc406Sopenharmony_ci
796141cc406Sopenharmony_ci  /* free scanner object memory */
797141cc406Sopenharmony_ci  free ((void *) s);
798141cc406Sopenharmony_ci}
799141cc406Sopenharmony_ci
800141cc406Sopenharmony_ci
801141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
802141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle h, SANE_Int n)
803141cc406Sopenharmony_ci{
804141cc406Sopenharmony_ci  TScanner *s;
805141cc406Sopenharmony_ci
806141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_get_option_descriptor %d\n", n);
807141cc406Sopenharmony_ci
808141cc406Sopenharmony_ci  if ((n < optCount) || (n >= optLast))
809141cc406Sopenharmony_ci    {
810141cc406Sopenharmony_ci      return NULL;
811141cc406Sopenharmony_ci    }
812141cc406Sopenharmony_ci
813141cc406Sopenharmony_ci  s = (TScanner *) h;
814141cc406Sopenharmony_ci  return &s->aOptions[n];
815141cc406Sopenharmony_ci}
816141cc406Sopenharmony_ci
817141cc406Sopenharmony_ci
818141cc406Sopenharmony_ciSANE_Status
819141cc406Sopenharmony_cisane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
820141cc406Sopenharmony_ci		     void *pVal, SANE_Int * pInfo)
821141cc406Sopenharmony_ci{
822141cc406Sopenharmony_ci  TScanner *s;
823141cc406Sopenharmony_ci  SANE_Int info;
824141cc406Sopenharmony_ci
825141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_control_option: option %d, action %d\n", n, Action);
826141cc406Sopenharmony_ci
827141cc406Sopenharmony_ci  s = (TScanner *) h;
828141cc406Sopenharmony_ci  info = 0;
829141cc406Sopenharmony_ci
830141cc406Sopenharmony_ci  switch (Action)
831141cc406Sopenharmony_ci    {
832141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
833141cc406Sopenharmony_ci      switch (n)
834141cc406Sopenharmony_ci	{
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_ci	  /* Get options of type SANE_Word */
837141cc406Sopenharmony_ci	case optBRX:
838141cc406Sopenharmony_ci	case optTLX:
839141cc406Sopenharmony_ci	  *(SANE_Word *) pVal = s->aValues[n].w;
840141cc406Sopenharmony_ci	  HP5400_DBG (DBG_MSG,
841141cc406Sopenharmony_ci	       "sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n,
842141cc406Sopenharmony_ci	       *(SANE_Word *) pVal);
843141cc406Sopenharmony_ci	  break;
844141cc406Sopenharmony_ci
845141cc406Sopenharmony_ci	case optBRY:
846141cc406Sopenharmony_ci	case optTLY:
847141cc406Sopenharmony_ci	  *(SANE_Word *) pVal = s->aValues[n].w;
848141cc406Sopenharmony_ci	  HP5400_DBG (DBG_MSG,
849141cc406Sopenharmony_ci	       "sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n,
850141cc406Sopenharmony_ci	       *(SANE_Word *) pVal);
851141cc406Sopenharmony_ci	  break;
852141cc406Sopenharmony_ci
853141cc406Sopenharmony_ci	case optCount:
854141cc406Sopenharmony_ci	case optDPI:
855141cc406Sopenharmony_ci	  HP5400_DBG (DBG_MSG,
856141cc406Sopenharmony_ci	       "sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n,
857141cc406Sopenharmony_ci	       (int) s->aValues[n].w);
858141cc406Sopenharmony_ci	  *(SANE_Word *) pVal = s->aValues[n].w;
859141cc406Sopenharmony_ci	  break;
860141cc406Sopenharmony_ci
861141cc406Sopenharmony_ci	  /* Get options of type SANE_Word array */
862141cc406Sopenharmony_ci	case optGammaTableRed:
863141cc406Sopenharmony_ci	case optGammaTableGreen:
864141cc406Sopenharmony_ci	case optGammaTableBlue:
865141cc406Sopenharmony_ci	  HP5400_DBG (DBG_MSG, "Reading gamma table\n");
866141cc406Sopenharmony_ci	  memcpy (pVal, s->aValues[n].wa, s->aOptions[n].size);
867141cc406Sopenharmony_ci	  break;
868141cc406Sopenharmony_ci
869141cc406Sopenharmony_ci	case optSensorScanTo:
870141cc406Sopenharmony_ci	case optSensorWeb:
871141cc406Sopenharmony_ci	case optSensorReprint:
872141cc406Sopenharmony_ci	case optSensorEmail:
873141cc406Sopenharmony_ci	case optSensorCopy:
874141cc406Sopenharmony_ci	case optSensorMoreOptions:
875141cc406Sopenharmony_ci	case optSensorCancel:
876141cc406Sopenharmony_ci	case optSensorPowerSave:
877141cc406Sopenharmony_ci	case optSensorCopiesUp:
878141cc406Sopenharmony_ci	case optSensorCopiesDown:
879141cc406Sopenharmony_ci        case optSensorColourBW:
880141cc406Sopenharmony_ci          {
881141cc406Sopenharmony_ci            HP5400_DBG (DBG_MSG, "Reading sensor state\n");
882141cc406Sopenharmony_ci
883141cc406Sopenharmony_ci            uint16_t sensorMap;
884141cc406Sopenharmony_ci            if (GetSensors(&s->HWParams, &sensorMap) != 0)
885141cc406Sopenharmony_ci              {
886141cc406Sopenharmony_ci                HP5400_DBG (DBG_ERR,
887141cc406Sopenharmony_ci                     "sane_control_option: SANE_ACTION_SET_VALUE could not retrieve sensors\n");
888141cc406Sopenharmony_ci                return SANE_STATUS_IO_ERROR;
889141cc406Sopenharmony_ci
890141cc406Sopenharmony_ci              }
891141cc406Sopenharmony_ci
892141cc406Sopenharmony_ci            HP5400_DBG (DBG_MSG, "Sensor state=%x\n", sensorMap);
893141cc406Sopenharmony_ci
894141cc406Sopenharmony_ci            // Add read flags to what we already have so that we can report them when requested.
895141cc406Sopenharmony_ci            s->sensorMap |= sensorMap;
896141cc406Sopenharmony_ci
897141cc406Sopenharmony_ci            // Look up the mask based on the option number.
898141cc406Sopenharmony_ci            uint16_t mask = sensorMaskMap[n - optGroupSensors - 1];
899141cc406Sopenharmony_ci            *(SANE_Word *) pVal = (s->sensorMap & mask)? 1:0;
900141cc406Sopenharmony_ci            s->sensorMap &= ~mask;
901141cc406Sopenharmony_ci            break;
902141cc406Sopenharmony_ci          }
903141cc406Sopenharmony_ci
904141cc406Sopenharmony_ci        case optSensorCopyCount:
905141cc406Sopenharmony_ci            {
906141cc406Sopenharmony_ci              HP5400_DBG (DBG_MSG, "Reading copy count\n");
907141cc406Sopenharmony_ci
908141cc406Sopenharmony_ci              TPanelInfo panelInfo;
909141cc406Sopenharmony_ci              if (GetPanelInfo(&s->HWParams, &panelInfo) != 0)
910141cc406Sopenharmony_ci                {
911141cc406Sopenharmony_ci                  HP5400_DBG (DBG_ERR,
912141cc406Sopenharmony_ci                       "sane_control_option: SANE_ACTION_SET_VALUE could not retrieve panel info\n");
913141cc406Sopenharmony_ci                  return SANE_STATUS_IO_ERROR;
914141cc406Sopenharmony_ci
915141cc406Sopenharmony_ci                }
916141cc406Sopenharmony_ci
917141cc406Sopenharmony_ci              HP5400_DBG (DBG_MSG, "Copy count setting=%u\n", panelInfo.copycount);
918141cc406Sopenharmony_ci              *(SANE_Word *) pVal = panelInfo.copycount;
919141cc406Sopenharmony_ci              break;
920141cc406Sopenharmony_ci            }
921141cc406Sopenharmony_ci
922141cc406Sopenharmony_ci        case optSensorColourBWState:
923141cc406Sopenharmony_ci            {
924141cc406Sopenharmony_ci              HP5400_DBG (DBG_MSG, "Reading BW/Colour setting\n");
925141cc406Sopenharmony_ci
926141cc406Sopenharmony_ci              TPanelInfo panelInfo;
927141cc406Sopenharmony_ci              if (GetPanelInfo(&s->HWParams, &panelInfo) != 0)
928141cc406Sopenharmony_ci                {
929141cc406Sopenharmony_ci                  HP5400_DBG (DBG_ERR,
930141cc406Sopenharmony_ci                       "sane_control_option: SANE_ACTION_SET_VALUE could not retrieve panel info\n");
931141cc406Sopenharmony_ci                  return SANE_STATUS_IO_ERROR;
932141cc406Sopenharmony_ci
933141cc406Sopenharmony_ci                }
934141cc406Sopenharmony_ci
935141cc406Sopenharmony_ci              HP5400_DBG (DBG_MSG, "BW/Colour setting=%u\n", panelInfo.bwcolour);
936141cc406Sopenharmony_ci
937141cc406Sopenharmony_ci              // Just for safety:
938141cc406Sopenharmony_ci              if (panelInfo.bwcolour < 1)
939141cc406Sopenharmony_ci                {
940141cc406Sopenharmony_ci                  panelInfo.bwcolour = 1;
941141cc406Sopenharmony_ci                }
942141cc406Sopenharmony_ci              else if (panelInfo.bwcolour > 2)
943141cc406Sopenharmony_ci                {
944141cc406Sopenharmony_ci                  panelInfo.bwcolour = 2;
945141cc406Sopenharmony_ci                }
946141cc406Sopenharmony_ci              (void)strcpy((SANE_String)pVal, modeSwitchList[panelInfo.bwcolour - 1]);
947141cc406Sopenharmony_ci              break;
948141cc406Sopenharmony_ci            }
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_ci#if 0
951141cc406Sopenharmony_ci	  /* Get options of type SANE_Bool */
952141cc406Sopenharmony_ci	case optLamp:
953141cc406Sopenharmony_ci	  GetLamp (&s->HWParams, &fLampIsOn);
954141cc406Sopenharmony_ci	  *(SANE_Bool *) pVal = fLampIsOn;
955141cc406Sopenharmony_ci	  break;
956141cc406Sopenharmony_ci
957141cc406Sopenharmony_ci	case optCalibrate:
958141cc406Sopenharmony_ci	  /*  although this option has nothing to read,
959141cc406Sopenharmony_ci	     it's added here to avoid a warning when running scanimage --help */
960141cc406Sopenharmony_ci	  break;
961141cc406Sopenharmony_ci#endif
962141cc406Sopenharmony_ci	default:
963141cc406Sopenharmony_ci	  HP5400_DBG (DBG_MSG, "SANE_ACTION_GET_VALUE: Invalid option (%d)\n", n);
964141cc406Sopenharmony_ci	}
965141cc406Sopenharmony_ci      break;
966141cc406Sopenharmony_ci
967141cc406Sopenharmony_ci
968141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
969141cc406Sopenharmony_ci      if (s->fScanning)
970141cc406Sopenharmony_ci	{
971141cc406Sopenharmony_ci	  HP5400_DBG (DBG_ERR,
972141cc406Sopenharmony_ci	       "sane_control_option: SANE_ACTION_SET_VALUE not allowed during scan\n");
973141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
974141cc406Sopenharmony_ci	}
975141cc406Sopenharmony_ci      switch (n)
976141cc406Sopenharmony_ci	{
977141cc406Sopenharmony_ci
978141cc406Sopenharmony_ci	case optCount:
979141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
980141cc406Sopenharmony_ci	  break;
981141cc406Sopenharmony_ci
982141cc406Sopenharmony_ci	case optBRX:
983141cc406Sopenharmony_ci	case optTLX:
984141cc406Sopenharmony_ci	  {
985141cc406Sopenharmony_ci            // Check against legal values.
986141cc406Sopenharmony_ci	    SANE_Word value = *(SANE_Word *) pVal;
987141cc406Sopenharmony_ci	    if ((value < s->aOptions[n].constraint.range->min) ||
988141cc406Sopenharmony_ci	        (value > s->aOptions[n].constraint.range->max))
989141cc406Sopenharmony_ci              {
990141cc406Sopenharmony_ci	        HP5400_DBG (DBG_ERR,
991141cc406Sopenharmony_ci	                   "sane_control_option: SANE_ACTION_SET_VALUE out of range X value\n");
992141cc406Sopenharmony_ci                return SANE_STATUS_INVAL;
993141cc406Sopenharmony_ci              }
994141cc406Sopenharmony_ci
995141cc406Sopenharmony_ci            info |= SANE_INFO_RELOAD_PARAMS;
996141cc406Sopenharmony_ci            s->ScanParams.iLines = 0;	/* Forget actual image settings */
997141cc406Sopenharmony_ci            s->aValues[n].w = value;
998141cc406Sopenharmony_ci            break;
999141cc406Sopenharmony_ci	  }
1000141cc406Sopenharmony_ci
1001141cc406Sopenharmony_ci        case optBRY:
1002141cc406Sopenharmony_ci        case optTLY:
1003141cc406Sopenharmony_ci          {
1004141cc406Sopenharmony_ci            // Check against legal values.
1005141cc406Sopenharmony_ci            SANE_Word value = *(SANE_Word *) pVal;
1006141cc406Sopenharmony_ci            if ((value < s->aOptions[n].constraint.range->min) ||
1007141cc406Sopenharmony_ci                (value > s->aOptions[n].constraint.range->max))
1008141cc406Sopenharmony_ci              {
1009141cc406Sopenharmony_ci                HP5400_DBG (DBG_ERR,
1010141cc406Sopenharmony_ci                           "sane_control_option: SANE_ACTION_SET_VALUE out of range Y value\n");
1011141cc406Sopenharmony_ci                return SANE_STATUS_INVAL;
1012141cc406Sopenharmony_ci              }
1013141cc406Sopenharmony_ci
1014141cc406Sopenharmony_ci            info |= SANE_INFO_RELOAD_PARAMS;
1015141cc406Sopenharmony_ci            s->ScanParams.iLines = 0;	/* Forget actual image settings */
1016141cc406Sopenharmony_ci            s->aValues[n].w = value;
1017141cc406Sopenharmony_ci            break;
1018141cc406Sopenharmony_ci          }
1019141cc406Sopenharmony_ci
1020141cc406Sopenharmony_ci        case optDPI:
1021141cc406Sopenharmony_ci          {
1022141cc406Sopenharmony_ci            // Check against legal values.
1023141cc406Sopenharmony_ci            SANE_Word dpiValue = *(SANE_Word *) pVal;
1024141cc406Sopenharmony_ci
1025141cc406Sopenharmony_ci            // First check too large.
1026141cc406Sopenharmony_ci            SANE_Word maxRes = setResolutions[setResolutions[0]];
1027141cc406Sopenharmony_ci            if (dpiValue > maxRes)
1028141cc406Sopenharmony_ci              {
1029141cc406Sopenharmony_ci                dpiValue = maxRes;
1030141cc406Sopenharmony_ci              }
1031141cc406Sopenharmony_ci            else // Check smaller values: if not exact match, pick next higher available.
1032141cc406Sopenharmony_ci              {
1033141cc406Sopenharmony_ci                for (SANE_Int resIdx = 1; resIdx <= setResolutions[0]; resIdx++)
1034141cc406Sopenharmony_ci                  {
1035141cc406Sopenharmony_ci                    if (dpiValue <= setResolutions[resIdx])
1036141cc406Sopenharmony_ci                      {
1037141cc406Sopenharmony_ci                        dpiValue = setResolutions[resIdx];
1038141cc406Sopenharmony_ci                        break;
1039141cc406Sopenharmony_ci                      }
1040141cc406Sopenharmony_ci                  }
1041141cc406Sopenharmony_ci              }
1042141cc406Sopenharmony_ci
1043141cc406Sopenharmony_ci            info |= SANE_INFO_RELOAD_PARAMS;
1044141cc406Sopenharmony_ci            s->ScanParams.iLines = 0;	/* Forget actual image settings */
1045141cc406Sopenharmony_ci            (s->aValues[n].w) = dpiValue;
1046141cc406Sopenharmony_ci            break;
1047141cc406Sopenharmony_ci          }
1048141cc406Sopenharmony_ci
1049141cc406Sopenharmony_ci	case optGammaTableRed:
1050141cc406Sopenharmony_ci	case optGammaTableGreen:
1051141cc406Sopenharmony_ci	case optGammaTableBlue:
1052141cc406Sopenharmony_ci	  HP5400_DBG (DBG_MSG, "Writing gamma table\n");
1053141cc406Sopenharmony_ci	  memcpy (s->aValues[n].wa, pVal, s->aOptions[n].size);
1054141cc406Sopenharmony_ci	  break;
1055141cc406Sopenharmony_ci
1056141cc406Sopenharmony_ci        case optSensorColourBWState:
1057141cc406Sopenharmony_ci            {
1058141cc406Sopenharmony_ci              SANE_String bwColour = (SANE_String)pVal;
1059141cc406Sopenharmony_ci              SANE_Word bwColourValue;
1060141cc406Sopenharmony_ci
1061141cc406Sopenharmony_ci              if (strcmp(bwColour, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1062141cc406Sopenharmony_ci                {
1063141cc406Sopenharmony_ci                  bwColourValue = 1;
1064141cc406Sopenharmony_ci                }
1065141cc406Sopenharmony_ci              else if (strcmp(bwColour, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1066141cc406Sopenharmony_ci                {
1067141cc406Sopenharmony_ci                  bwColourValue = 2;
1068141cc406Sopenharmony_ci                }
1069141cc406Sopenharmony_ci              else
1070141cc406Sopenharmony_ci                {
1071141cc406Sopenharmony_ci                  HP5400_DBG (DBG_ERR,
1072141cc406Sopenharmony_ci                       "sane_control_option: SANE_ACTION_SET_VALUE invalid colour/bw mode\n");
1073141cc406Sopenharmony_ci                  return SANE_STATUS_INVAL;
1074141cc406Sopenharmony_ci                }
1075141cc406Sopenharmony_ci
1076141cc406Sopenharmony_ci              HP5400_DBG (DBG_MSG, "Setting BW/Colour state=%d\n", bwColourValue);
1077141cc406Sopenharmony_ci
1078141cc406Sopenharmony_ci              /*
1079141cc406Sopenharmony_ci               * Now write it with the other panel settings back to the scanner.
1080141cc406Sopenharmony_ci               *
1081141cc406Sopenharmony_ci               */
1082141cc406Sopenharmony_ci              if (SetColourBW(&s->HWParams, bwColourValue) != 0)
1083141cc406Sopenharmony_ci                {
1084141cc406Sopenharmony_ci                  HP5400_DBG (DBG_ERR,
1085141cc406Sopenharmony_ci                       "sane_control_option: SANE_ACTION_SET_VALUE could not set colour/BW mode\n");
1086141cc406Sopenharmony_ci                  return SANE_STATUS_IO_ERROR;
1087141cc406Sopenharmony_ci                }
1088141cc406Sopenharmony_ci              break;
1089141cc406Sopenharmony_ci            }
1090141cc406Sopenharmony_ci
1091141cc406Sopenharmony_ci        case optSensorCopyCount:
1092141cc406Sopenharmony_ci            {
1093141cc406Sopenharmony_ci              SANE_Word copyCount = *(SANE_Word *) pVal;
1094141cc406Sopenharmony_ci              if (copyCount < 0)
1095141cc406Sopenharmony_ci                {
1096141cc406Sopenharmony_ci                  copyCount = 0;
1097141cc406Sopenharmony_ci                }
1098141cc406Sopenharmony_ci              else if (copyCount > 99)
1099141cc406Sopenharmony_ci                {
1100141cc406Sopenharmony_ci                  copyCount = 99;
1101141cc406Sopenharmony_ci                }
1102141cc406Sopenharmony_ci
1103141cc406Sopenharmony_ci              HP5400_DBG (DBG_MSG, "Setting Copy Count=%d\n", copyCount);
1104141cc406Sopenharmony_ci
1105141cc406Sopenharmony_ci              /*
1106141cc406Sopenharmony_ci               * Now write it with the other panel settings back to the scanner.
1107141cc406Sopenharmony_ci               *
1108141cc406Sopenharmony_ci               */
1109141cc406Sopenharmony_ci              if (SetCopyCount(&s->HWParams, copyCount) != 0)
1110141cc406Sopenharmony_ci                {
1111141cc406Sopenharmony_ci                  HP5400_DBG (DBG_ERR,
1112141cc406Sopenharmony_ci                       "sane_control_option: SANE_ACTION_SET_VALUE could not set copy count\n");
1113141cc406Sopenharmony_ci                  return SANE_STATUS_IO_ERROR;
1114141cc406Sopenharmony_ci
1115141cc406Sopenharmony_ci                }
1116141cc406Sopenharmony_ci              break;
1117141cc406Sopenharmony_ci            }
1118141cc406Sopenharmony_ci
1119141cc406Sopenharmony_ci/*
1120141cc406Sopenharmony_ci    case optLamp:
1121141cc406Sopenharmony_ci      fVal = *(SANE_Bool *)pVal;
1122141cc406Sopenharmony_ci      HP5400_DBG(DBG_MSG, "lamp %s\n", fVal ? "on" : "off");
1123141cc406Sopenharmony_ci      SetLamp(&s->HWParams, fVal);
1124141cc406Sopenharmony_ci      break;
1125141cc406Sopenharmony_ci*/
1126141cc406Sopenharmony_ci#if 0
1127141cc406Sopenharmony_ci	case optCalibrate:
1128141cc406Sopenharmony_ci/*       SimpleCalib(&s->HWParams); */
1129141cc406Sopenharmony_ci	  break;
1130141cc406Sopenharmony_ci#endif
1131141cc406Sopenharmony_ci	default:
1132141cc406Sopenharmony_ci	  HP5400_DBG (DBG_ERR, "SANE_ACTION_SET_VALUE: Invalid option (%d)\n", n);
1133141cc406Sopenharmony_ci	}
1134141cc406Sopenharmony_ci      if (pInfo != NULL)
1135141cc406Sopenharmony_ci	{
1136141cc406Sopenharmony_ci	  *pInfo = info;
1137141cc406Sopenharmony_ci	}
1138141cc406Sopenharmony_ci      break;
1139141cc406Sopenharmony_ci
1140141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
1141141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
1142141cc406Sopenharmony_ci
1143141cc406Sopenharmony_ci
1144141cc406Sopenharmony_ci    default:
1145141cc406Sopenharmony_ci      HP5400_DBG (DBG_ERR, "Invalid action (%d)\n", Action);
1146141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1147141cc406Sopenharmony_ci    }
1148141cc406Sopenharmony_ci
1149141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1150141cc406Sopenharmony_ci}
1151141cc406Sopenharmony_ci
1152141cc406Sopenharmony_ci
1153141cc406Sopenharmony_ci
1154141cc406Sopenharmony_ciSANE_Status
1155141cc406Sopenharmony_cisane_get_parameters (SANE_Handle h, SANE_Parameters * p)
1156141cc406Sopenharmony_ci{
1157141cc406Sopenharmony_ci  TScanner *s;
1158141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_get_parameters\n");
1159141cc406Sopenharmony_ci
1160141cc406Sopenharmony_ci  s = (TScanner *) h;
1161141cc406Sopenharmony_ci
1162141cc406Sopenharmony_ci  /* first do some checks */
1163141cc406Sopenharmony_ci  if (s->aValues[optTLX].w >= s->aValues[optBRX].w)
1164141cc406Sopenharmony_ci    {
1165141cc406Sopenharmony_ci      HP5400_DBG (DBG_ERR, "TLX should be smaller than BRX\n");
1166141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;	/* proper error code? */
1167141cc406Sopenharmony_ci    }
1168141cc406Sopenharmony_ci  if (s->aValues[optTLY].w >= s->aValues[optBRY].w)
1169141cc406Sopenharmony_ci    {
1170141cc406Sopenharmony_ci      HP5400_DBG (DBG_ERR, "TLY should be smaller than BRY\n");
1171141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;	/* proper error code? */
1172141cc406Sopenharmony_ci    }
1173141cc406Sopenharmony_ci
1174141cc406Sopenharmony_ci  /* return the data */
1175141cc406Sopenharmony_ci  p->format = SANE_FRAME_RGB;
1176141cc406Sopenharmony_ci  p->last_frame = SANE_TRUE;
1177141cc406Sopenharmony_ci
1178141cc406Sopenharmony_ci  p->depth = 8;
1179141cc406Sopenharmony_ci  if (s->ScanParams.iLines)	/* Initialised by doing a scan */
1180141cc406Sopenharmony_ci    {
1181141cc406Sopenharmony_ci      p->pixels_per_line = s->ScanParams.iBytesPerLine / 3;
1182141cc406Sopenharmony_ci      p->lines = s->ScanParams.iLines;
1183141cc406Sopenharmony_ci      p->bytes_per_line = s->ScanParams.iBytesPerLine;
1184141cc406Sopenharmony_ci    }
1185141cc406Sopenharmony_ci  else
1186141cc406Sopenharmony_ci    {
1187141cc406Sopenharmony_ci      p->lines = MM_TO_PIXEL (s->aValues[optBRY].w - s->aValues[optTLY].w,
1188141cc406Sopenharmony_ci			      s->aValues[optDPI].w);
1189141cc406Sopenharmony_ci      p->pixels_per_line =
1190141cc406Sopenharmony_ci	MM_TO_PIXEL (s->aValues[optBRX].w - s->aValues[optTLX].w,
1191141cc406Sopenharmony_ci		     s->aValues[optDPI].w);
1192141cc406Sopenharmony_ci      p->bytes_per_line = p->pixels_per_line * 3;
1193141cc406Sopenharmony_ci    }
1194141cc406Sopenharmony_ci
1195141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1196141cc406Sopenharmony_ci}
1197141cc406Sopenharmony_ci
1198141cc406Sopenharmony_ci#define BUFFER_READ_HEADER_SIZE 32
1199141cc406Sopenharmony_ci
1200141cc406Sopenharmony_ciSANE_Status
1201141cc406Sopenharmony_cisane_start (SANE_Handle h)
1202141cc406Sopenharmony_ci{
1203141cc406Sopenharmony_ci  TScanner *s;
1204141cc406Sopenharmony_ci  SANE_Parameters par;
1205141cc406Sopenharmony_ci
1206141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_start\n");
1207141cc406Sopenharmony_ci
1208141cc406Sopenharmony_ci  s = (TScanner *) h;
1209141cc406Sopenharmony_ci
1210141cc406Sopenharmony_ci  if (sane_get_parameters (h, &par) != SANE_STATUS_GOOD)
1211141cc406Sopenharmony_ci    {
1212141cc406Sopenharmony_ci      HP5400_DBG (DBG_MSG, "Invalid scan parameters (sane_get_parameters)\n");
1213141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1214141cc406Sopenharmony_ci    }
1215141cc406Sopenharmony_ci  s->iLinesLeft = par.lines;
1216141cc406Sopenharmony_ci
1217141cc406Sopenharmony_ci  /* fill in the scanparams using the option values */
1218141cc406Sopenharmony_ci  s->ScanParams.iDpi = s->aValues[optDPI].w;
1219141cc406Sopenharmony_ci  s->ScanParams.iLpi = s->aValues[optDPI].w;
1220141cc406Sopenharmony_ci
1221141cc406Sopenharmony_ci  /* Guessing here. 75dpi => 1, 2400dpi => 32 */
1222141cc406Sopenharmony_ci  /*  s->ScanParams.iColourOffset = s->aValues[optDPI].w / 75; */
1223141cc406Sopenharmony_ci  /* now we don't need correction => corrected by scan request type ? */
1224141cc406Sopenharmony_ci  s->ScanParams.iColourOffset = 0;
1225141cc406Sopenharmony_ci
1226141cc406Sopenharmony_ci  s->ScanParams.iTop =
1227141cc406Sopenharmony_ci    MM_TO_PIXEL (s->aValues[optTLY].w + s->HWParams.iTopLeftY, HW_LPI);
1228141cc406Sopenharmony_ci  s->ScanParams.iLeft =
1229141cc406Sopenharmony_ci    MM_TO_PIXEL (s->aValues[optTLX].w + s->HWParams.iTopLeftX, HW_DPI);
1230141cc406Sopenharmony_ci
1231141cc406Sopenharmony_ci  /* Note: All measurements passed to the scanning routines must be in HW_LPI */
1232141cc406Sopenharmony_ci  s->ScanParams.iWidth =
1233141cc406Sopenharmony_ci    MM_TO_PIXEL (s->aValues[optBRX].w - s->aValues[optTLX].w, HW_LPI);
1234141cc406Sopenharmony_ci  s->ScanParams.iHeight =
1235141cc406Sopenharmony_ci    MM_TO_PIXEL (s->aValues[optBRY].w - s->aValues[optTLY].w, HW_LPI);
1236141cc406Sopenharmony_ci
1237141cc406Sopenharmony_ci  /* After the scanning, the iLines and iBytesPerLine will be filled in */
1238141cc406Sopenharmony_ci
1239141cc406Sopenharmony_ci  /* copy gamma table */
1240141cc406Sopenharmony_ci  WriteGammaCalibTable (s->HWParams.iXferHandle, s->aGammaTableR,
1241141cc406Sopenharmony_ci			s->aGammaTableG, s->aGammaTableB);
1242141cc406Sopenharmony_ci
1243141cc406Sopenharmony_ci  /* prepare the actual scan */
1244141cc406Sopenharmony_ci  /* We say normal here. In future we should have a preview flag to set preview mode */
1245141cc406Sopenharmony_ci  if (InitScan (SCAN_TYPE_NORMAL, &s->ScanParams, &s->HWParams) != 0)
1246141cc406Sopenharmony_ci    {
1247141cc406Sopenharmony_ci      HP5400_DBG (DBG_MSG, "Invalid scan parameters (InitScan)\n");
1248141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1249141cc406Sopenharmony_ci    }
1250141cc406Sopenharmony_ci
1251141cc406Sopenharmony_ci  /* for the moment no lines has been read */
1252141cc406Sopenharmony_ci  s->ScanParams.iLinesRead = 0;
1253141cc406Sopenharmony_ci
1254141cc406Sopenharmony_ci  s->fScanning = TRUE;
1255141cc406Sopenharmony_ci  s->fCanceled = FALSE;
1256141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1257141cc406Sopenharmony_ci}
1258141cc406Sopenharmony_ci
1259141cc406Sopenharmony_ci
1260141cc406Sopenharmony_ciSANE_Status
1261141cc406Sopenharmony_cisane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len)
1262141cc406Sopenharmony_ci{
1263141cc406Sopenharmony_ci
1264141cc406Sopenharmony_ci  /* Read actual scan from the circular buffer */
1265141cc406Sopenharmony_ci  /* Note: this is already color corrected, though some work still needs to be done
1266141cc406Sopenharmony_ci     to deal with the colour offsetting */
1267141cc406Sopenharmony_ci  TScanner *s;
1268141cc406Sopenharmony_ci  char *buffer = (char*)buf;
1269141cc406Sopenharmony_ci
1270141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_read: request %d bytes \n", maxlen);
1271141cc406Sopenharmony_ci
1272141cc406Sopenharmony_ci  s = (TScanner *) h;
1273141cc406Sopenharmony_ci
1274141cc406Sopenharmony_ci  /* nothing has been read for the moment */
1275141cc406Sopenharmony_ci  *len = 0;
1276141cc406Sopenharmony_ci  if (!s->fScanning || s->fCanceled)
1277141cc406Sopenharmony_ci    {
1278141cc406Sopenharmony_ci      HP5400_DBG (DBG_MSG, "sane_read: we're not scanning.\n");
1279141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
1280141cc406Sopenharmony_ci    }
1281141cc406Sopenharmony_ci
1282141cc406Sopenharmony_ci
1283141cc406Sopenharmony_ci  /* if we read all the lines return EOF */
1284141cc406Sopenharmony_ci  if (s->ScanParams.iLinesRead == s->ScanParams.iLines)
1285141cc406Sopenharmony_ci    {
1286141cc406Sopenharmony_ci/*    FinishScan( &s->HWParams );        *** FinishScan called in sane_cancel */
1287141cc406Sopenharmony_ci      HP5400_DBG (DBG_MSG, "sane_read: EOF\n");
1288141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
1289141cc406Sopenharmony_ci    }
1290141cc406Sopenharmony_ci
1291141cc406Sopenharmony_ci  /* read as many lines the buffer may contain and while there are lines to be read */
1292141cc406Sopenharmony_ci  while ((*len + s->ScanParams.iBytesPerLine <= maxlen)
1293141cc406Sopenharmony_ci	 && (s->ScanParams.iLinesRead < s->ScanParams.iLines))
1294141cc406Sopenharmony_ci    {
1295141cc406Sopenharmony_ci
1296141cc406Sopenharmony_ci      /* get one more line from the circular buffer */
1297141cc406Sopenharmony_ci      CircBufferGetLine (s->HWParams.iXferHandle, &s->HWParams.pipe, buffer);
1298141cc406Sopenharmony_ci
1299141cc406Sopenharmony_ci      /* increment pointer, size and line number */
1300141cc406Sopenharmony_ci      buffer += s->ScanParams.iBytesPerLine;
1301141cc406Sopenharmony_ci      *len += s->ScanParams.iBytesPerLine;
1302141cc406Sopenharmony_ci      s->ScanParams.iLinesRead++;
1303141cc406Sopenharmony_ci    }
1304141cc406Sopenharmony_ci
1305141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_read: %d bytes read\n", *len);
1306141cc406Sopenharmony_ci
1307141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1308141cc406Sopenharmony_ci}
1309141cc406Sopenharmony_ci
1310141cc406Sopenharmony_ci
1311141cc406Sopenharmony_civoid
1312141cc406Sopenharmony_cisane_cancel (SANE_Handle h)
1313141cc406Sopenharmony_ci{
1314141cc406Sopenharmony_ci  TScanner *s;
1315141cc406Sopenharmony_ci
1316141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_cancel\n");
1317141cc406Sopenharmony_ci
1318141cc406Sopenharmony_ci  s = (TScanner *) h;
1319141cc406Sopenharmony_ci
1320141cc406Sopenharmony_ci  /* to be implemented more thoroughly */
1321141cc406Sopenharmony_ci
1322141cc406Sopenharmony_ci  /* Make sure the scanner head returns home */
1323141cc406Sopenharmony_ci  FinishScan (&s->HWParams);
1324141cc406Sopenharmony_ci
1325141cc406Sopenharmony_ci  s->fCanceled = TRUE;
1326141cc406Sopenharmony_ci  s->fScanning = FALSE;
1327141cc406Sopenharmony_ci}
1328141cc406Sopenharmony_ci
1329141cc406Sopenharmony_ci
1330141cc406Sopenharmony_ciSANE_Status
1331141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle h, SANE_Bool m)
1332141cc406Sopenharmony_ci{
1333141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_set_io_mode %s\n", m ? "non-blocking" : "blocking");
1334141cc406Sopenharmony_ci
1335141cc406Sopenharmony_ci  /* prevent compiler from complaining about unused parameters */
1336141cc406Sopenharmony_ci  (void) h;
1337141cc406Sopenharmony_ci
1338141cc406Sopenharmony_ci  if (m)
1339141cc406Sopenharmony_ci    {
1340141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
1341141cc406Sopenharmony_ci    }
1342141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1343141cc406Sopenharmony_ci}
1344141cc406Sopenharmony_ci
1345141cc406Sopenharmony_ci
1346141cc406Sopenharmony_ciSANE_Status
1347141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle h, SANE_Int * fd)
1348141cc406Sopenharmony_ci{
1349141cc406Sopenharmony_ci  HP5400_DBG (DBG_MSG, "sane_select_fd\n");
1350141cc406Sopenharmony_ci
1351141cc406Sopenharmony_ci  /* prevent compiler from complaining about unused parameters */
1352141cc406Sopenharmony_ci  (void) h;
1353141cc406Sopenharmony_ci  (void) fd;
1354141cc406Sopenharmony_ci
1355141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
1356141cc406Sopenharmony_ci}
1357