1 /*
2   Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl)
3 
4   This program is free software; you can redistribute it and/or
5   modify it under the terms of the GNU General Public License
6   as published by the Free Software Foundation; either version 2
7   of the License, or (at your option) any later version.
8 
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13 
14   You should have received a copy of the GNU General Public License
15   along with this program.  If not, see <https://www.gnu.org/licenses/>.
16 */
17 
18 /*
19     Concept for a backend for scanners based on the NIASH chipset,
20     such as HP3300C, HP3400C, HP4300C, Agfa Touch.
21     Parts of this source were inspired by other backends.
22 */
23 
24 #include "../include/sane/config.h"
25 #include "../include/sane/sane.h"
26 #include "../include/sane/sanei.h"
27 #include "../include/sane/sanei_backend.h"
28 #include "../include/sane/sanei_config.h"
29 #include "../include/sane/saneopts.h"
30 
31 #include <stdlib.h>             /* malloc, free */
32 #include <string.h>             /* memcpy */
33 #include <stdio.h>
34 #include <sys/time.h>
35 #include <sys/wait.h>
36 
37 /* definitions for debug */
38 #define BACKEND_NAME niash
39 #define BUILD 1
40 
41 #define DBG_ASSERT  1
42 #define DBG_ERR     16
43 #define DBG_MSG     32
44 
45 /* Just to avoid conflicts between niash backend and testtool */
46 #define WITH_NIASH 1
47 
48 
49 /* (source) includes for data transfer methods */
50 #define STATIC static
51 
52 #include "niash_core.c"
53 #include "niash_xfer.c"
54 
55 
56 #define ASSERT(cond) (!(cond) ? DBG(DBG_ASSERT, "!!! ASSERT(%S) FAILED!!!\n",STRINGIFY(cond));)
57 
58 
59 #define MM_TO_PIXEL(_mm_, _dpi_)    ((_mm_) * (_dpi_) / 25.4 )
60 #define PIXEL_TO_MM(_pixel_, _dpi_) ((_pixel_) * 25.4 / (_dpi_) )
61 
62 
63 /* options enumerator */
64 typedef enum
65 {
66   optCount = 0,
67 
68   optGroupGeometry,
69   optTLX, optTLY, optBRX, optBRY,
70   optDPI,
71 
72   optGroupImage,
73   optGammaTable,                /* gamma table */
74 
75   optGroupMode,
76   optMode,
77 
78   optGroupEnhancement,
79   optThreshold,
80 
81 #ifdef EXPERIMENTAL
82   optGroupMisc,
83   optLamp,
84 
85   optCalibrate,
86   optGamma,                      /* analog gamma = single number */
87 #endif
88   optLast
89 } EOptionIndex;
90 
91 
92 typedef union
93 {
94   SANE_Word w;
95   SANE_Word *wa;                /* word array */
96   SANE_String s;
97 } TOptionValue;
98 
99 #define HW_GAMMA_SIZE 4096
100 #define SANE_GAMMA_SIZE 4096
101 
102 typedef struct
103 {
104   SANE_Option_Descriptor aOptions[optLast];
105   TOptionValue aValues[optLast];
106 
107   TScanParams ScanParams;
108   THWParams HWParams;
109 
110   TDataPipe DataPipe;
111   int iLinesLeft;               /* lines to scan */
112   int iBytesLeft;               /* bytes to read */
113   int iPixelsPerLine;           /* pixels in one scan line */
114 
115   SANE_Int aGammaTable[SANE_GAMMA_SIZE];        /* a 12-to-8 bit color lookup table */
116 
117   /* fCancelled needed to let sane issue the cancel message
118      instead of an error message */
119   SANE_Bool fCancelled;         /* SANE_TRUE if scanning cancelled */
120 
121   SANE_Bool fScanning;          /* SANE_TRUE if actively scanning */
122 
123   int WarmUpTime;               /* time to wait before a calibration starts */
124   unsigned char CalWhite[3];    /* values for the last calibration of white */
125   struct timeval WarmUpStarted;
126   /* system type to trace the time elapsed */
127 } TScanner;
128 
129 
130 /* linked list of SANE_Device structures */
131 typedef struct TDevListEntry
132 {
133   struct TDevListEntry *pNext;
134   SANE_Device dev;
135 } TDevListEntry;
136 
137 
138 static TDevListEntry *_pFirstSaneDev = 0;
139 static int iNumSaneDev = 0;
140 static const SANE_Device **_pSaneDevList = 0;
141 
142 
143 /* option constraints */
144 static const SANE_Range rangeGammaTable = { 0, 255, 1 };
145 
146 /* available scanner resolutions */
147 static const SANE_Int setResolutions[] = { 4, 75, 150, 300, 600 };
148 
149 #ifdef EXPERIMENTAL
150 /* range of an analog gamma */
151 static const SANE_Range rangeGamma = { SANE_FIX (0.25), SANE_FIX (4.0),
152   SANE_FIX (0.0)
153 };
154 #endif
155 
156 /* interpolate a sane gamma table to a hardware appropriate one
157    just in case the sane gamma table would be smaller */
158 static void
_ConvertGammaTable(SANE_Word * saneGamma,unsigned char * hwGamma)159 _ConvertGammaTable (SANE_Word * saneGamma, unsigned char *hwGamma)
160 {
161   int i;
162   int current = 0;
163   for (i = 0; i < SANE_GAMMA_SIZE; ++i)
164     {
165       int j;
166       int next;
167 
168       /* highest range of copy indices */
169       next = ((i + 1) * HW_GAMMA_SIZE) / SANE_GAMMA_SIZE;
170 
171       /* always copy the first */
172       hwGamma[current] = saneGamma[i];
173 
174       /* the interpolation of the rest depends on the gap */
175       for (j = current + 1; j < HW_GAMMA_SIZE && j < next; ++j)
176         {
177           hwGamma[j] =
178             (saneGamma[i] * (next - j) +
179              saneGamma[i + 1] * (j - current)) / (next - current);
180         }
181       current = next;
182     }
183 }
184 
185 /* create a unity gamma table */
186 static void
_UnityGammaTable(unsigned char * hwGamma)187 _UnityGammaTable (unsigned char *hwGamma)
188 {
189   int i;
190   for (i = 0; i < HW_GAMMA_SIZE; ++i)
191     {
192       hwGamma[i] = (i * 256) / HW_GAMMA_SIZE;
193     }
194 
195 }
196 
197 static const SANE_Range rangeXmm = { 0, 220, 1 };
198 static const SANE_Range rangeYmm = { 0, 296, 1 };
199 static const SANE_Int startUpGamma = SANE_FIX (1.6);
200 
201 static const char colorStr[] = { SANE_VALUE_SCAN_MODE_COLOR };
202 static const char grayStr[] = { SANE_VALUE_SCAN_MODE_GRAY };
203 static const char lineartStr[] = { SANE_VALUE_SCAN_MODE_LINEART };
204 
205 #define DEPTH_LINEART  1
206 #define DEPTH_GRAY     8
207 #define DEPTH_COLOR    8
208 
209 #define BYTES_PER_PIXEL_GRAY   1
210 #define BYTES_PER_PIXEL_COLOR  3
211 
212 #define BITS_PER_PIXEL_LINEART 1
213 #define BITS_PER_PIXEL_GRAY    DEPTH_GRAY
214 #define BITS_PER_PIXEL_COLOR   (DEPTH_COLOR*3)
215 
216 #define BITS_PER_BYTE  8
217 #define BITS_PADDING   (BITS_PER_BYTE-1)
218 
219 #define MODE_COLOR   0
220 #define MODE_GRAY    1
221 #define MODE_LINEART 2
222 
223 /* lineart threshold range */
224 static const SANE_Range rangeThreshold = {
225   0,
226   100,
227   1
228 };
229 
230 /* scanning modes */
231 static SANE_String_Const modeList[] = {
232   colorStr,
233   grayStr,
234   lineartStr,
235   NULL
236 };
237 
238 static int
_bytesPerLineLineart(int pixelsPerLine)239 _bytesPerLineLineart (int pixelsPerLine)
240 {
241   return (pixelsPerLine * BITS_PER_PIXEL_LINEART +
242           BITS_PADDING) / BITS_PER_BYTE;
243 }
244 
245 static int
_bytesPerLineGray(int pixelsPerLine)246 _bytesPerLineGray (int pixelsPerLine)
247 {
248   return (pixelsPerLine * BITS_PER_PIXEL_GRAY + BITS_PADDING) / BITS_PER_BYTE;
249 }
250 
251 static int
_bytesPerLineColor(int pixelsPerLine)252 _bytesPerLineColor (int pixelsPerLine)
253 {
254   return (pixelsPerLine * BITS_PER_PIXEL_COLOR +
255           BITS_PADDING) / BITS_PER_BYTE;
256 }
257 
258 
259 /* dummy*/
260 static void
_rgb2rgb(unsigned char __sane_unused__ * buffer,int __sane_unused__ pixels,int __sane_unused__ threshold)261 _rgb2rgb (unsigned char __sane_unused__ *buffer, int __sane_unused__ pixels, int __sane_unused__ threshold)
262 {
263   /* make the compiler content */
264 }
265 
266 
267 /* convert 24bit RGB to 8bit GRAY */
268 static void
_rgb2gray(unsigned char * buffer,int pixels,int __sane_unused__ threshold)269 _rgb2gray (unsigned char *buffer, int pixels, int __sane_unused__ threshold)
270 {
271 #define WEIGHT_R 27
272 #define WEIGHT_G 54
273 #define WEIGHT_B 19
274 #define WEIGHT_W (WEIGHT_R + WEIGHT_G + WEIGHT_B)
275   static int aWeight[BYTES_PER_PIXEL_COLOR] =
276     { WEIGHT_R, WEIGHT_G, WEIGHT_B };
277   int nbyte = pixels * BYTES_PER_PIXEL_COLOR;
278   int acc = 0;
279   int x;
280 
281   for (x = 0; x < nbyte; ++x)
282     {
283       acc += aWeight[x % BYTES_PER_PIXEL_COLOR] * buffer[x];
284       if ((x + 1) % BYTES_PER_PIXEL_COLOR == 0)
285         {
286           buffer[x / BYTES_PER_PIXEL_COLOR] =
287             (unsigned char) (acc / WEIGHT_W);
288           acc = 0;
289         }
290     }
291 #undef WEIGHT_R
292 #undef WEIGHT_G
293 #undef WEIGHT_B
294 #undef WEIGHT_W
295 }
296 
297 /* convert 24bit RGB to 1bit B/W */
298 static void
_rgb2lineart(unsigned char * buffer,int pixels,int threshold)299 _rgb2lineart (unsigned char *buffer, int pixels, int threshold)
300 {
301   static const int aMask[BITS_PER_BYTE] = { 128, 64, 32, 16, 8, 4, 2, 1 };
302   int acc = 0;
303   int nx;
304   int x;
305   int thresh;
306   _rgb2gray (buffer, pixels, 0);
307   nx = ((pixels + BITS_PADDING) / BITS_PER_BYTE) * BITS_PER_BYTE;
308   thresh = 255 * threshold / rangeThreshold.max;
309   for (x = 0; x < nx; ++x)
310     {
311       if (x < pixels && buffer[x] < thresh)
312         {
313           acc |= aMask[x % BITS_PER_BYTE];
314         }
315       if ((x + 1) % BITS_PER_BYTE == 0)
316         {
317           buffer[x / BITS_PER_BYTE] = (unsigned char) (acc);
318           acc = 0;
319         }
320     }
321 }
322 
323 typedef struct tgModeParam
324 {
325   SANE_Int depth;
326   SANE_Frame format;
327   int (*bytesPerLine) (int pixelsPerLine);
328   void (*adaptFormat) (unsigned char *rgbBuffer, int pixels, int threshold);
329 
330 } TModeParam;
331 
332 static const TModeParam modeParam[] = {
333   {DEPTH_COLOR, SANE_FRAME_RGB, _bytesPerLineColor, _rgb2rgb},
334   {DEPTH_GRAY, SANE_FRAME_GRAY, _bytesPerLineGray, _rgb2gray},
335   {DEPTH_LINEART, SANE_FRAME_GRAY, _bytesPerLineLineart, _rgb2lineart}
336 };
337 
338 
339 #define WARMUP_AFTERSTART    1  /* flag for 1st warm up */
340 #define WARMUP_INSESSION     0
341 #define WARMUP_TESTINTERVAL 15  /* test every 15sec */
342 #define WARMUP_TIME         30  /* first wait is 30sec minimum */
343 #define WARMUP_MAXTIME      90  /* after one and a half minute start latest */
344 
345 #define CAL_DEV_MAX         15
346 /* maximum deviation of cal values in percent between 2 tests */
347 
348 /* different warm up after start and after automatic off */
349 static const int aiWarmUpTime[] = { WARMUP_TESTINTERVAL, WARMUP_TIME };
350 
351 
352 
353 /* returns 1, when the warm up time "iTime" has elasped */
354 static int
_TimeElapsed(struct timeval * start,struct timeval * now,int iTime)355 _TimeElapsed (struct timeval *start, struct timeval *now, int iTime)
356 {
357 
358   /* this is a bit strange, but can deal with overflows */
359   if (start->tv_sec > now->tv_sec)
360     return (start->tv_sec / 2 - now->tv_sec / 2 > iTime / 2);
361   else
362     return (now->tv_sec - start->tv_sec >= iTime);
363 }
364 
365 static void
_WarmUpLamp(TScanner * s,int iMode)366 _WarmUpLamp (TScanner * s, int iMode)
367 {
368   SANE_Bool fLampOn;
369   /* on startup don't care what was before
370      assume lamp was off, and the previous
371      cal values can never be reached */
372   if (iMode == WARMUP_AFTERSTART)
373     {
374       fLampOn = SANE_FALSE;
375       s->CalWhite[0] = s->CalWhite[1] = s->CalWhite[2] = (unsigned char) (-1);
376     }
377   else
378     GetLamp (&s->HWParams, &fLampOn);
379 
380   if (!fLampOn)
381     {
382       /* get the current system time */
383       gettimeofday (&s->WarmUpStarted, 0);
384       /* determine the time to wait at least */
385       s->WarmUpTime = aiWarmUpTime[iMode];
386       /* switch on the lamp */
387       SetLamp (&s->HWParams, SANE_TRUE);
388     }
389 }
390 
391 static void
_WaitForLamp(TScanner * s,unsigned char * pabCalibTable)392 _WaitForLamp (TScanner * s, unsigned char *pabCalibTable)
393 {
394   struct timeval now[2];        /* toggling time holder */
395   int i;                        /* rgb loop */
396   int iCal = 0;                 /* counter */
397   int iCurrent = 0;             /* buffer and time-holder swap flag */
398   SANE_Bool fHasCal;
399   unsigned char CalWhite[2][3]; /* toggling buffer */
400   int iDelay = 0;               /* delay loop counter */
401   _WarmUpLamp (s, SANE_FALSE);
402 
403 
404   /* get the time stamp for the wait loops */
405   if (s->WarmUpTime)
406     gettimeofday (&now[iCurrent], 0);
407   SimpleCalibExt (&s->HWParams, pabCalibTable, CalWhite[iCurrent]);
408   fHasCal = SANE_TRUE;
409 
410   DBG (DBG_MSG, "_WaitForLamp: first calibration\n");
411 
412 
413   /* wait until time has elapsed or for values to stabilze */
414   while (s->WarmUpTime)
415     {
416       /* check if the last scan has lower calibration values than
417          the current one would have */
418       if (s->WarmUpTime && fHasCal)
419         {
420           SANE_Bool fOver = SANE_TRUE;
421           for (i = 0; fOver && i < 3; ++i)
422             {
423               if (!s->CalWhite[i])
424                 fOver = SANE_FALSE;
425               else if (CalWhite[iCurrent][i] < s->CalWhite[i])
426                 fOver = SANE_FALSE;
427             }
428 
429           /* warm up is not needed, when calibration data is above
430              the calibration data of the last scan */
431           if (fOver)
432             {
433               s->WarmUpTime = 0;
434               DBG (DBG_MSG,
435                    "_WaitForLamp: Values seem stable, skipping next calibration cycle\n");
436             }
437         }
438 
439 
440       /* break the loop, when the longest wait time has expired
441          to prevent a hanging application,
442          even if the values might not be good, yet */
443       if (s->WarmUpTime && fHasCal && iCal)
444         {
445           /* abort, when we have waited long enough */
446           if (_TimeElapsed
447               (&s->WarmUpStarted, &now[iCurrent], WARMUP_MAXTIME))
448             {
449               /* stop idling */
450               s->WarmUpTime = 0;
451               DBG (DBG_MSG, "_WaitForLamp: WARMUP_MAXTIME=%ds elapsed!\n",
452                    WARMUP_MAXTIME);
453             }
454         }
455 
456 
457       /* enter a delay loop, when there is still time to wait */
458       if (s->WarmUpTime)
459         {
460           /* if the (too low) calibration values have just been acquired
461              we start waiting */
462           if (fHasCal)
463             DBG (DBG_MSG, "_WaitForLamp: entering delay loop\r");
464           else
465             DBG (DBG_MSG, "_WaitForLamp: delay loop %d        \r", ++iDelay);
466           sleep (1);
467           fHasCal = SANE_FALSE;
468           gettimeofday (&now[!iCurrent], 0);
469         }
470 
471 
472       /* look if we should check again */
473       if (s->WarmUpTime         /* did we have to wait at all */
474           /* is the minimum time elapsed */
475           && _TimeElapsed (&s->WarmUpStarted, &now[!iCurrent], s->WarmUpTime)
476           /* has the minimum time elapsed since the last calibration */
477           && _TimeElapsed (&now[iCurrent], &now[!iCurrent],
478                            WARMUP_TESTINTERVAL))
479         {
480           int dev = 0;          /* 0 percent deviation in cal value as default */
481           iDelay = 0;           /* all delays processed */
482           /* new calibration */
483           ++iCal;
484           iCurrent = !iCurrent; /* swap the test-buffer, and time-holder */
485           SimpleCalibExt (&s->HWParams, pabCalibTable, CalWhite[iCurrent]);
486           fHasCal = SANE_TRUE;
487 
488           for (i = 0; i < 3; ++i)
489             {
490               /* copy for faster and clearer access */
491               int cwa;
492               int cwb;
493               int ldev;
494               cwa = CalWhite[!iCurrent][i];
495               cwb = CalWhite[iCurrent][i];
496               /* find the biggest deviation of one color */
497               if (cwa > cwb)
498                 ldev = 0;
499               else if (cwa && cwb)
500                 ldev = ((cwb - cwa) * 100) / cwb;
501               else
502                 ldev = 100;
503               dev = MAX (dev, ldev);
504             }
505 
506           /* show the biggest deviation of the calibration values */
507           DBG (DBG_MSG, "_WaitForLamp: recalibration #%d, deviation = %d%%\n",
508                iCal, dev);
509 
510           /* the deviation to the previous calibration is tolerable */
511           if (dev <= CAL_DEV_MAX)
512             s->WarmUpTime = 0;
513         }
514     }
515 
516   /* remember the values of this calibration
517      for the next time */
518   for (i = 0; i < 3; ++i)
519     {
520       s->CalWhite[i] = CalWhite[iCurrent][i];
521     }
522 }
523 
524 
525 /* used, when setting gamma as 1 value */
526 static void
_SetScalarGamma(SANE_Int * aiGamma,SANE_Int sfGamma)527 _SetScalarGamma (SANE_Int * aiGamma, SANE_Int sfGamma)
528 {
529   int j;
530   double fGamma;
531   fGamma = SANE_UNFIX (sfGamma);
532   for (j = 0; j < SANE_GAMMA_SIZE; j++)
533     {
534       int iData;
535       iData =
536         floor (256.0 *
537                pow (((double) j / (double) SANE_GAMMA_SIZE), 1.0 / fGamma));
538       if (iData > 255)
539         iData = 255;
540       aiGamma[j] = iData;
541     }
542 }
543 
544 
545 /* return size of longest string in a string list */
546 static size_t
_MaxStringSize(const SANE_String_Const strings[])547 _MaxStringSize (const SANE_String_Const strings[])
548 {
549   size_t size, max_size = 0;
550   int i;
551 
552   for (i = 0; strings[i]; ++i)
553     {
554       size = strlen (strings[i]) + 1;
555       if (size > max_size)
556         max_size = size;
557     }
558   return max_size;
559 }
560 
561 
562 /* change a sane cap and return true, when a change took place */
563 static int
_ChangeCap(SANE_Word * pCap,SANE_Word cap,int isSet)564 _ChangeCap (SANE_Word * pCap, SANE_Word cap, int isSet)
565 {
566   SANE_Word prevCap = *pCap;
567   if (isSet)
568     {
569       *pCap |= cap;
570     }
571   else
572     {
573       *pCap &= ~cap;
574     }
575   return *pCap != prevCap;
576 }
577 
578 
579 static void
_InitOptions(TScanner * s)580 _InitOptions (TScanner * s)
581 {
582   int i;
583   SANE_Option_Descriptor *pDesc;
584   TOptionValue *pVal;
585   _SetScalarGamma (s->aGammaTable, startUpGamma);
586 
587   for (i = optCount; i < optLast; i++)
588     {
589 
590       pDesc = &s->aOptions[i];
591       pVal = &s->aValues[i];
592 
593       /* defaults */
594       pDesc->name = "";
595       pDesc->title = "";
596       pDesc->desc = "";
597       pDesc->type = SANE_TYPE_INT;
598       pDesc->unit = SANE_UNIT_NONE;
599       pDesc->size = sizeof (SANE_Word);
600       pDesc->constraint_type = SANE_CONSTRAINT_NONE;
601       pDesc->cap = 0;
602 
603       switch (i)
604         {
605 
606         case optCount:
607           pDesc->title = SANE_TITLE_NUM_OPTIONS;
608           pDesc->desc = SANE_DESC_NUM_OPTIONS;
609           pDesc->cap = SANE_CAP_SOFT_DETECT;
610           pVal->w = (SANE_Word) optLast;
611           break;
612 
613         case optGroupGeometry:
614           pDesc->title = "Geometry";
615           pDesc->type = SANE_TYPE_GROUP;
616           pDesc->size = 0;
617           break;
618 
619         case optTLX:
620           pDesc->name = SANE_NAME_SCAN_TL_X;
621           pDesc->title = SANE_TITLE_SCAN_TL_X;
622           pDesc->desc = SANE_DESC_SCAN_TL_X;
623           pDesc->unit = SANE_UNIT_MM;
624           pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
625           pDesc->constraint.range = &rangeXmm;
626           pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
627           pVal->w = rangeXmm.min;
628           break;
629 
630         case optTLY:
631           pDesc->name = SANE_NAME_SCAN_TL_Y;
632           pDesc->title = SANE_TITLE_SCAN_TL_Y;
633           pDesc->desc = SANE_DESC_SCAN_TL_Y;
634           pDesc->unit = SANE_UNIT_MM;
635           pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
636           pDesc->constraint.range = &rangeYmm;
637           pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
638           pVal->w = rangeYmm.min;
639           break;
640 
641         case optBRX:
642           pDesc->name = SANE_NAME_SCAN_BR_X;
643           pDesc->title = SANE_TITLE_SCAN_BR_X;
644           pDesc->desc = SANE_DESC_SCAN_BR_X;
645           pDesc->unit = SANE_UNIT_MM;
646           pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
647           pDesc->constraint.range = &rangeXmm;
648           pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
649           pVal->w = 210 /* A4 width instead of rangeXmm.max */ ;
650           break;
651 
652         case optBRY:
653           pDesc->name = SANE_NAME_SCAN_BR_Y;
654           pDesc->title = SANE_TITLE_SCAN_BR_Y;
655           pDesc->desc = SANE_DESC_SCAN_BR_Y;
656           pDesc->unit = SANE_UNIT_MM;
657           pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
658           pDesc->constraint.range = &rangeYmm;
659           pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
660           pVal->w = 290 /* have a bit reserve instead of rangeYmm.max */ ;
661           break;
662 
663         case optDPI:
664           pDesc->name = SANE_NAME_SCAN_RESOLUTION;
665           pDesc->title = SANE_TITLE_SCAN_RESOLUTION;
666           pDesc->desc = SANE_DESC_SCAN_RESOLUTION;
667           pDesc->unit = SANE_UNIT_DPI;
668           pDesc->constraint_type = SANE_CONSTRAINT_WORD_LIST;
669           pDesc->constraint.word_list = setResolutions;
670           pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
671           pVal->w = setResolutions[2];  /* default to 150dpi */
672           break;
673 
674         case optGroupImage:
675           pDesc->title = SANE_I18N ("Image");
676           pDesc->type = SANE_TYPE_GROUP;
677           pDesc->size = 0;
678           break;
679 
680 #ifdef EXPERIMENTAL
681         case optGamma:
682           pDesc->name = SANE_NAME_ANALOG_GAMMA;
683           pDesc->title = SANE_TITLE_ANALOG_GAMMA;
684           pDesc->desc = SANE_DESC_ANALOG_GAMMA;
685           pDesc->type = SANE_TYPE_FIXED;
686           pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
687           pDesc->constraint.range = &rangeGamma;
688           pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
689           pVal->w = startUpGamma;
690           break;
691 #endif
692 
693         case optGammaTable:
694           pDesc->name = SANE_NAME_GAMMA_VECTOR;
695           pDesc->title = SANE_TITLE_GAMMA_VECTOR;
696           pDesc->desc = SANE_DESC_GAMMA_VECTOR;
697           pDesc->size = sizeof (s->aGammaTable);
698           pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
699           pDesc->constraint.range = &rangeGammaTable;
700           pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
701           pVal->wa = s->aGammaTable;
702           break;
703 
704 #ifdef EXPERIMENTAL
705         case optGroupMisc:
706           pDesc->title = SANE_I18N ("Miscellaneous");
707           pDesc->type = SANE_TYPE_GROUP;
708           pDesc->size = 0;
709           break;
710 
711         case optLamp:
712           pDesc->name = "lamp";
713           pDesc->title = SANE_I18N ("Lamp status");
714           pDesc->desc = SANE_I18N ("Switches the lamp on or off.");
715           pDesc->type = SANE_TYPE_BOOL;
716           pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
717           /* switch the lamp on when starting for first the time */
718           pVal->w = SANE_TRUE;
719           break;
720 
721         case optCalibrate:
722           pDesc->name = "calibrate";
723           pDesc->title = SANE_I18N ("Calibrate");
724           pDesc->desc = SANE_I18N ("Calibrates for black and white level.");
725           pDesc->type = SANE_TYPE_BUTTON;
726           pDesc->cap = SANE_CAP_SOFT_SELECT;
727           pDesc->size = 0;
728           break;
729 #endif
730         case optGroupMode:
731           pDesc->title = SANE_I18N ("Scan Mode");
732           pDesc->desc = "";
733           pDesc->type = SANE_TYPE_GROUP;
734           break;
735 
736         case optMode:
737           /* scan mode */
738           pDesc->name = SANE_NAME_SCAN_MODE;
739           pDesc->title = SANE_TITLE_SCAN_MODE;
740           pDesc->desc = SANE_DESC_SCAN_MODE;
741           pDesc->type = SANE_TYPE_STRING;
742           pDesc->size = _MaxStringSize (modeList);
743           pDesc->constraint_type = SANE_CONSTRAINT_STRING_LIST;
744           pDesc->constraint.string_list = modeList;
745           pDesc->cap =
746             SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_EMULATED;
747           pVal->w = MODE_COLOR;
748           break;
749 
750         case optGroupEnhancement:
751           pDesc->title = SANE_I18N ("Enhancement");
752           pDesc->desc = "";
753           pDesc->type = SANE_TYPE_GROUP;
754           break;
755 
756         case optThreshold:
757           pDesc->name = SANE_NAME_THRESHOLD;
758           pDesc->title = SANE_TITLE_THRESHOLD;
759           pDesc->desc = SANE_DESC_THRESHOLD;
760           pDesc->type = SANE_TYPE_INT;
761           pDesc->unit = SANE_UNIT_PERCENT;
762           pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
763           pDesc->constraint.range = &rangeThreshold;
764           pDesc->cap =
765             SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE |
766             SANE_CAP_EMULATED;
767           pVal->w = 50;
768           break;
769 
770         default:
771           DBG (DBG_ERR, "Uninitialised option %d\n", i);
772           break;
773         }
774     }
775 }
776 
777 
778 static int
_ReportDevice(TScannerModel * pModel,const char * pszDeviceName)779 _ReportDevice (TScannerModel * pModel, const char *pszDeviceName)
780 {
781   TDevListEntry *pNew, *pDev;
782 
783   DBG (DBG_MSG, "niash: _ReportDevice '%s'\n", pszDeviceName);
784 
785   pNew = malloc (sizeof (TDevListEntry));
786   if (!pNew)
787     {
788       DBG (DBG_ERR, "no mem\n");
789       return -1;
790     }
791 
792   /* add new element to the end of the list */
793   if (_pFirstSaneDev == 0)
794     {
795       _pFirstSaneDev = pNew;
796     }
797   else
798     {
799       for (pDev = _pFirstSaneDev; pDev->pNext; pDev = pDev->pNext)
800         {
801           ;
802         }
803       pDev->pNext = pNew;
804     }
805 
806   /* fill in new element */
807   pNew->pNext = 0;
808   pNew->dev.name = strdup (pszDeviceName);
809   pNew->dev.vendor = pModel->pszVendor;
810   pNew->dev.model = pModel->pszName;
811   pNew->dev.type = "flatbed scanner";
812 
813   iNumSaneDev++;
814 
815   return 0;
816 }
817 
818 
819 
820 /*****************************************************************************/
821 
822 SANE_Status
sane_init(SANE_Int * piVersion,SANE_Auth_Callback __sane_unused__ pfnAuth)823 sane_init (SANE_Int * piVersion, SANE_Auth_Callback __sane_unused__ pfnAuth)
824 {
825   DBG_INIT ();
826   DBG (DBG_MSG, "sane_init\n");
827 
828   if (piVersion != NULL)
829     {
830       *piVersion = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, BUILD);
831     }
832 
833   /* initialise transfer methods */
834   iNumSaneDev = 0;
835   NiashXferInit (_ReportDevice);
836 
837   return SANE_STATUS_GOOD;
838 }
839 
840 
841 void
sane_exit(void)842 sane_exit (void)
843 {
844   TDevListEntry *pDev, *pNext;
845 
846   DBG (DBG_MSG, "sane_exit\n");
847 
848   /* free device list memory */
849   if (_pSaneDevList)
850     {
851       for (pDev = _pFirstSaneDev; pDev; pDev = pNext)
852         {
853           pNext = pDev->pNext;
854           free ((void *) pDev->dev.name);
855           free (pDev);
856         }
857       _pFirstSaneDev = 0;
858       free (_pSaneDevList);
859       _pSaneDevList = 0;
860     }
861 }
862 
863 
864 SANE_Status
sane_get_devices(const SANE_Device *** device_list,SANE_Bool __sane_unused__ local_only)865 sane_get_devices (const SANE_Device *** device_list, SANE_Bool __sane_unused__ local_only)
866 {
867   TDevListEntry *pDev;
868   int i;
869 
870   DBG (DBG_MSG, "sane_get_devices\n");
871 
872   if (_pSaneDevList)
873     {
874       free (_pSaneDevList);
875     }
876 
877   _pSaneDevList = malloc (sizeof (*_pSaneDevList) * (iNumSaneDev + 1));
878   if (!_pSaneDevList)
879     {
880       DBG (DBG_MSG, "no mem\n");
881       return SANE_STATUS_NO_MEM;
882     }
883   i = 0;
884   for (pDev = _pFirstSaneDev; pDev; pDev = pDev->pNext)
885     {
886       _pSaneDevList[i++] = &pDev->dev;
887     }
888   _pSaneDevList[i++] = 0;       /* last entry is 0 */
889 
890   *device_list = _pSaneDevList;
891 
892   return SANE_STATUS_GOOD;
893 }
894 
895 
896 SANE_Status
sane_open(SANE_String_Const name,SANE_Handle * h)897 sane_open (SANE_String_Const name, SANE_Handle * h)
898 {
899   TScanner *s;
900 
901   DBG (DBG_MSG, "sane_open: %s\n", name);
902 
903   /* check the name */
904   if (strlen (name) == 0)
905     {
906       /* default to first available device */
907       name = _pFirstSaneDev->dev.name;
908     }
909 
910   s = malloc (sizeof (TScanner));
911   if (!s)
912     {
913       DBG (DBG_MSG, "malloc failed\n");
914       return SANE_STATUS_NO_MEM;
915     }
916 
917   if (NiashOpen (&s->HWParams, name) < 0)
918     {
919       /* is this OK ? */
920       DBG (DBG_ERR, "NiashOpen failed\n");
921       free ((void *) s);
922       return SANE_STATUS_DEVICE_BUSY;
923     }
924   _InitOptions (s);
925   s->fScanning = SANE_FALSE;
926   s->fCancelled = SANE_FALSE;
927   *h = s;
928 
929   /* Turn on lamp by default at startup */
930   _WarmUpLamp (s, WARMUP_AFTERSTART);
931 
932   return SANE_STATUS_GOOD;
933 }
934 
935 
936 void
sane_close(SANE_Handle h)937 sane_close (SANE_Handle h)
938 {
939   TScanner *s;
940 
941   DBG (DBG_MSG, "sane_close\n");
942 
943   s = (TScanner *) h;
944 
945   /* turn off scanner lamp */
946   SetLamp (&s->HWParams, SANE_FALSE);
947 
948   /* close scanner */
949   NiashClose (&s->HWParams);
950 
951   /* free scanner object memory */
952   free ((void *) s);
953 }
954 
955 
956 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle h,SANE_Int n)957 sane_get_option_descriptor (SANE_Handle h, SANE_Int n)
958 {
959   TScanner *s;
960 
961   DBG (DBG_MSG, "sane_get_option_descriptor %d\n", n);
962 
963   if ((n < optCount) || (n >= optLast))
964     {
965       return NULL;
966     }
967 
968   s = (TScanner *) h;
969   return &s->aOptions[n];
970 }
971 
972 
973 SANE_Status
sane_control_option(SANE_Handle h,SANE_Int n,SANE_Action Action,void * pVal,SANE_Int * pInfo)974 sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
975                      void *pVal, SANE_Int * pInfo)
976 {
977   TScanner *s;
978   static char szTable[100];
979   int *pi;
980   int i;
981   SANE_Int info;
982   SANE_Status status;
983 #ifdef EXPERIMENTAL
984   SANE_Bool fLampIsOn;
985   SANE_Bool fVal;
986   SANE_Bool fSame;
987 #endif
988 
989   DBG (DBG_MSG, "sane_control_option: option %d, action %d\n", n, Action);
990 
991   if ((n < optCount) || (n >= optLast))
992     {
993       return SANE_STATUS_UNSUPPORTED;
994     }
995 
996   if (Action == SANE_ACTION_GET_VALUE || Action == SANE_ACTION_SET_VALUE)
997     {
998       if (pVal == NULL)
999         {
1000           return SANE_STATUS_INVAL;
1001         }
1002     }
1003 
1004   s = (TScanner *) h;
1005   info = 0;
1006 
1007   switch (Action)
1008     {
1009     case SANE_ACTION_GET_VALUE:
1010       switch (n)
1011         {
1012 
1013           /* Get options of type SANE_Word */
1014         case optCount:
1015         case optDPI:
1016 #ifdef EXPERIMENTAL
1017         case optGamma:
1018 #endif
1019         case optTLX:
1020         case optTLY:
1021         case optBRX:
1022         case optBRY:
1023         case optThreshold:
1024           DBG (DBG_MSG,
1025                "sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n,
1026                (int) s->aValues[n].w);
1027           *(SANE_Word *) pVal = s->aValues[n].w;
1028           break;
1029 
1030           /* Get options of type SANE_Word array */
1031         case optGammaTable:
1032           DBG (DBG_MSG, "Reading gamma table\n");
1033           memcpy (pVal, s->aValues[n].wa, s->aOptions[n].size);
1034           break;
1035 
1036         case optMode:
1037           DBG (DBG_MSG, "Reading scan mode %s\n",
1038                modeList[s->aValues[optMode].w]);
1039           strcpy ((char *) pVal, modeList[s->aValues[optMode].w]);
1040           break;
1041 
1042 #ifdef EXPERIMENTAL
1043           /* Get options of type SANE_Bool */
1044         case optLamp:
1045           GetLamp (&s->HWParams, &fLampIsOn);
1046           *(SANE_Bool *) pVal = fLampIsOn;
1047           break;
1048 
1049         case optCalibrate:
1050           /*  although this option has nothing to read,
1051              it's added here to avoid a warning when running scanimage --help */
1052           break;
1053 #endif
1054 
1055         default:
1056           DBG (DBG_MSG, "SANE_ACTION_GET_VALUE: Invalid option (%d)\n", n);
1057         }
1058       break;
1059 
1060 
1061     case SANE_ACTION_SET_VALUE:
1062       if (s->fScanning)
1063         {
1064           DBG (DBG_ERR,
1065                "sane_control_option: SANE_ACTION_SET_VALUE not allowed during scan\n");
1066           return SANE_STATUS_INVAL;
1067         }
1068       switch (n)
1069         {
1070 
1071         case optCount:
1072           return SANE_STATUS_INVAL;
1073 
1074 #ifdef EXPERIMENTAL
1075         case optGamma:
1076 #endif
1077         case optThreshold:
1078         case optDPI:
1079 
1080           info |= SANE_INFO_RELOAD_PARAMS;
1081           /* fall through */
1082 
1083         case optTLX:
1084         case optTLY:
1085         case optBRX:
1086         case optBRY:
1087 
1088           status = sanei_constrain_value (&s->aOptions[n], pVal, &info);
1089           if (status != SANE_STATUS_GOOD)
1090             {
1091               DBG (DBG_ERR, "Failed to constrain option %d (%s)\n", n,
1092                    s->aOptions[n].title);
1093               return status;
1094             }
1095 
1096 #ifdef EXPERIMENTAL
1097           /* check values if they are equal */
1098           fSame = s->aValues[n].w == *(SANE_Word *) pVal;
1099 #endif
1100 
1101           /* set the values */
1102           s->aValues[n].w = *(SANE_Word *) pVal;
1103           DBG (DBG_MSG,
1104                "sane_control_option: SANE_ACTION_SET_VALUE %d = %d\n", n,
1105                (int) s->aValues[n].w);
1106 #ifdef EXPERIMENTAL
1107           if (n == optGamma)
1108             {
1109               if (!fSame && optLast > optGammaTable)
1110                 {
1111                   info |= SANE_INFO_RELOAD_OPTIONS;
1112                 }
1113               _SetScalarGamma (s->aGammaTable, s->aValues[n].w);
1114             }
1115 #endif
1116           break;
1117 
1118         case optGammaTable:
1119           DBG (DBG_MSG, "Writing gamma table\n");
1120           pi = (SANE_Int *) pVal;
1121           memcpy (s->aValues[n].wa, pVal, s->aOptions[n].size);
1122 
1123           /* prepare table for debug */
1124           strcpy (szTable, "Gamma table summary:");
1125           for (i = 0; i < SANE_GAMMA_SIZE; i++)
1126             {
1127               if ((SANE_GAMMA_SIZE / 16) && (i % (SANE_GAMMA_SIZE / 16)) == 0)
1128                 {
1129                   DBG (DBG_MSG, "%s\n", szTable);
1130 		  szTable[0] = '\0';
1131                 }
1132               /* test for number print */
1133               if ((SANE_GAMMA_SIZE / 64) && (i % (SANE_GAMMA_SIZE / 64)) == 0)
1134                 {
1135                   sprintf (szTable + strlen(szTable), " %04X", pi[i]);
1136                 }
1137             }
1138           if (strlen (szTable))
1139             {
1140               DBG (DBG_MSG, "%s\n", szTable);
1141             }
1142           break;
1143 
1144         case optMode:
1145           {
1146             SANE_Word *pCap;
1147             int fCapChanged = 0;
1148 
1149             pCap = &s->aOptions[optThreshold].cap;
1150 
1151             if (strcmp ((char const *) pVal, colorStr) == 0)
1152               {
1153                 s->aValues[optMode].w = MODE_COLOR;
1154                 fCapChanged = _ChangeCap (pCap, SANE_CAP_INACTIVE, 1);
1155               }
1156             if (strcmp ((char const *) pVal, grayStr) == 0)
1157               {
1158                 s->aValues[optMode].w = MODE_GRAY;
1159                 fCapChanged = _ChangeCap (pCap, SANE_CAP_INACTIVE, 1);
1160               }
1161             if (strcmp ((char const *) pVal, lineartStr) == 0)
1162               {
1163                 s->aValues[optMode].w = MODE_LINEART;
1164                 fCapChanged = _ChangeCap (pCap, SANE_CAP_INACTIVE, 0);
1165 
1166               }
1167             info |= SANE_INFO_RELOAD_PARAMS;
1168             if (fCapChanged)
1169               {
1170                 info |= SANE_INFO_RELOAD_OPTIONS;
1171               }
1172             DBG (DBG_MSG, "setting scan mode: %s\n", (char const *) pVal);
1173           }
1174           break;
1175 
1176 
1177 
1178 #ifdef EXPERIMENTAL
1179         case optLamp:
1180           fVal = *(SANE_Bool *) pVal;
1181           DBG (DBG_MSG, "lamp %s\n", fVal ? "on" : "off");
1182           if (fVal)
1183             _WarmUpLamp (s, WARMUP_INSESSION);
1184           else
1185             SetLamp (&s->HWParams, SANE_FALSE);
1186           break;
1187 
1188         case optCalibrate:
1189 /*       SimpleCalib(&s->HWParams); */
1190           break;
1191 #endif
1192 
1193         default:
1194           DBG (DBG_ERR, "SANE_ACTION_SET_VALUE: Invalid option (%d)\n", n);
1195         }
1196       if (pInfo != NULL)
1197         {
1198           *pInfo |= info;
1199         }
1200       break;
1201 
1202 
1203     case SANE_ACTION_SET_AUTO:
1204       return SANE_STATUS_UNSUPPORTED;
1205 
1206 
1207     default:
1208       DBG (DBG_ERR, "Invalid action (%d)\n", Action);
1209       return SANE_STATUS_INVAL;
1210     }
1211 
1212   return SANE_STATUS_GOOD;
1213 }
1214 
1215 
1216 
1217 
1218 
1219 SANE_Status
sane_get_parameters(SANE_Handle h,SANE_Parameters * p)1220 sane_get_parameters (SANE_Handle h, SANE_Parameters * p)
1221 {
1222   TScanner *s;
1223   TModeParam const *pMode;
1224 
1225   DBG (DBG_MSG, "sane_get_parameters\n");
1226 
1227   s = (TScanner *) h;
1228 
1229   /* first do some checks */
1230   if (s->aValues[optTLX].w >= s->aValues[optBRX].w)
1231     {
1232       DBG (DBG_ERR, "TLX should be smaller than BRX\n");
1233       return SANE_STATUS_INVAL; /* proper error code? */
1234     }
1235   if (s->aValues[optTLY].w >= s->aValues[optBRY].w)
1236     {
1237       DBG (DBG_ERR, "TLY should be smaller than BRY\n");
1238       return SANE_STATUS_INVAL; /* proper error code? */
1239     }
1240 
1241 
1242   pMode = &modeParam[s->aValues[optMode].w];
1243 
1244   /* return the data */
1245   p->format = pMode->format;
1246   p->last_frame = SANE_TRUE;
1247 
1248   p->lines = MM_TO_PIXEL (s->aValues[optBRY].w - s->aValues[optTLY].w,
1249                           s->aValues[optDPI].w);
1250   p->depth = pMode->depth;
1251   p->pixels_per_line =
1252     MM_TO_PIXEL (s->aValues[optBRX].w - s->aValues[optTLX].w,
1253                  s->aValues[optDPI].w);
1254   p->bytes_per_line = pMode->bytesPerLine (p->pixels_per_line);
1255 
1256   return SANE_STATUS_GOOD;
1257 }
1258 
1259 
1260 /* get the scale down factor for a resolution that is
1261   not supported by hardware */
1262 static int
_SaneEmulateScaling(int iDpi)1263 _SaneEmulateScaling (int iDpi)
1264 {
1265   if (iDpi == 75)
1266     return 2;
1267   else
1268     return 1;
1269 }
1270 
1271 
1272 SANE_Status
sane_start(SANE_Handle h)1273 sane_start (SANE_Handle h)
1274 {
1275   TScanner *s;
1276   SANE_Parameters par;
1277   int iLineCorr;
1278   int iScaleDown;
1279   static unsigned char abGamma[HW_GAMMA_SIZE];
1280   static unsigned char abCalibTable[HW_PIXELS * 6];
1281 
1282   DBG (DBG_MSG, "sane_start\n");
1283 
1284   s = (TScanner *) h;
1285 
1286   if (sane_get_parameters (h, &par) != SANE_STATUS_GOOD)
1287     {
1288       DBG (DBG_MSG, "Invalid scan parameters\n");
1289       return SANE_STATUS_INVAL;
1290     }
1291   iScaleDown = _SaneEmulateScaling (s->aValues[optDPI].w);
1292   s->iLinesLeft = par.lines;
1293 
1294   /* fill in the scanparams using the option values */
1295   s->ScanParams.iDpi = s->aValues[optDPI].w * iScaleDown;
1296   s->ScanParams.iLpi = s->aValues[optDPI].w * iScaleDown;
1297 
1298   /* calculate correction for filling of circular buffer */
1299   iLineCorr = 3 * s->HWParams.iSensorSkew;      /* usually 16 motor steps */
1300   /* calculate correction for garbage lines */
1301   iLineCorr += s->HWParams.iSkipLines * (HW_LPI / s->ScanParams.iLpi);
1302 
1303   s->ScanParams.iTop =
1304     MM_TO_PIXEL (s->aValues[optTLY].w + s->HWParams.iTopLeftY,
1305                  HW_LPI) - iLineCorr;
1306   s->ScanParams.iLeft =
1307     MM_TO_PIXEL (s->aValues[optTLX].w + s->HWParams.iTopLeftX, HW_DPI);
1308 
1309   s->ScanParams.iWidth = par.pixels_per_line * iScaleDown;
1310   s->ScanParams.iHeight = par.lines * iScaleDown;
1311   s->ScanParams.iBottom = HP3300C_BOTTOM;
1312   s->ScanParams.fCalib = SANE_FALSE;
1313 
1314   /* perform a simple calibration just before scanning */
1315   _WaitForLamp (s, abCalibTable);
1316 
1317   if (s->aValues[optMode].w == MODE_LINEART)
1318     {
1319       /* use a unity gamma table for lineart to be independent from Gamma settings */
1320       _UnityGammaTable (abGamma);
1321     }
1322   else
1323     {
1324       /* copy gamma table */
1325       _ConvertGammaTable (s->aGammaTable, abGamma);
1326     }
1327 
1328   WriteGammaCalibTable (abGamma, abGamma, abGamma, abCalibTable, 0, 0,
1329                         &s->HWParams);
1330 
1331   /* prepare the actual scan */
1332   if (!InitScan (&s->ScanParams, &s->HWParams))
1333     {
1334       DBG (DBG_MSG, "Invalid scan parameters\n");
1335       return SANE_STATUS_INVAL;
1336     }
1337 
1338   /* init data pipe */
1339   s->DataPipe.iSkipLines = s->HWParams.iSkipLines;
1340   /* on the hp3400 and hp4300 we cannot set the top of the scan area (yet),
1341      so instead we just scan and throw away the data until the top */
1342   if (s->HWParams.fReg07)
1343     {
1344       s->DataPipe.iSkipLines +=
1345         MM_TO_PIXEL (s->aValues[optTLY].w + s->HWParams.iTopLeftY,
1346                      s->aValues[optDPI].w * iScaleDown);
1347     }
1348   s->iBytesLeft = 0;
1349   s->iPixelsPerLine = par.pixels_per_line;
1350 
1351   /* hack */
1352   s->DataPipe.pabLineBuf = (unsigned char *) malloc (HW_PIXELS * 3);
1353   CircBufferInit (s->HWParams.iXferHandle, &s->DataPipe,
1354                   par.pixels_per_line, s->ScanParams.iHeight,
1355                   s->ScanParams.iLpi * s->HWParams.iSensorSkew / HW_LPI,
1356                   s->HWParams.iReversedHead, iScaleDown, iScaleDown);
1357 
1358   s->fScanning = SANE_TRUE;
1359   s->fCancelled = SANE_FALSE;
1360   return SANE_STATUS_GOOD;
1361 }
1362 
1363 
1364 SANE_Status
sane_read(SANE_Handle h,SANE_Byte * buf,SANE_Int maxlen,SANE_Int * len)1365 sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len)
1366 {
1367   TScanner *s;
1368   TDataPipe *p;
1369   TModeParam const *pMode;
1370 
1371   DBG (DBG_MSG, "sane_read: buf=%p, maxlen=%d, ", buf, maxlen);
1372 
1373   s = (TScanner *) h;
1374 
1375   pMode = &modeParam[s->aValues[optMode].w];
1376 
1377   /* sane_read only allowed after sane_start */
1378   if (!s->fScanning)
1379     {
1380       if (s->fCancelled)
1381         {
1382           DBG (DBG_MSG, "\n");
1383           DBG (DBG_MSG, "sane_read: sane_read cancelled\n");
1384           s->fCancelled = SANE_FALSE;
1385           return SANE_STATUS_CANCELLED;
1386         }
1387       else
1388         {
1389           DBG (DBG_ERR,
1390                "sane_read: sane_read only allowed after sane_start\n");
1391           return SANE_STATUS_INVAL;
1392         }
1393     }
1394 
1395   p = &s->DataPipe;
1396 
1397   /* anything left to read? */
1398   if ((s->iLinesLeft == 0) && (s->iBytesLeft == 0))
1399     {
1400       CircBufferExit (p);
1401       free (p->pabLineBuf);
1402       p->pabLineBuf = NULL;
1403       FinishScan (&s->HWParams);
1404       *len = 0;
1405       DBG (DBG_MSG, "\n");
1406       DBG (DBG_MSG, "sane_read: end of scan\n");
1407       s->fCancelled = SANE_FALSE;
1408       s->fScanning = SANE_FALSE;
1409       return SANE_STATUS_EOF;
1410     }
1411 
1412   /* time to read the next line? */
1413   if (s->iBytesLeft == 0)
1414     {
1415       /* read a line from the transfer buffer */
1416       if (CircBufferGetLineEx (s->HWParams.iXferHandle, p, p->pabLineBuf,
1417                                s->HWParams.iReversedHead, SANE_TRUE))
1418         {
1419           pMode->adaptFormat (p->pabLineBuf, s->iPixelsPerLine,
1420                               s->aValues[optThreshold].w);
1421           s->iBytesLeft = pMode->bytesPerLine (s->iPixelsPerLine);
1422           s->iLinesLeft--;
1423         }
1424       /* stop scanning further, when the read action fails
1425          because we try read after the end of the buffer */
1426       else
1427         {
1428           FinishScan (&s->HWParams);
1429           CircBufferExit (p);
1430           free (p->pabLineBuf);
1431           p->pabLineBuf = NULL;
1432           *len = 0;
1433           DBG (DBG_MSG, "\n");
1434           DBG (DBG_MSG, "sane_read: read after end of buffer\n");
1435           s->fCancelled = SANE_FALSE;
1436           s->fScanning = SANE_FALSE;
1437           return SANE_STATUS_EOF;
1438         }
1439 
1440     }
1441 
1442   /* copy (part of) a line */
1443   *len = MIN (maxlen, s->iBytesLeft);
1444   memcpy (buf,
1445           &p->pabLineBuf[pMode->bytesPerLine (s->iPixelsPerLine) -
1446                          s->iBytesLeft], *len);
1447   s->iBytesLeft -= *len;
1448 
1449   DBG (DBG_MSG, " read=%d    \n", *len);
1450 
1451   return SANE_STATUS_GOOD;
1452 }
1453 
1454 
1455 void
sane_cancel(SANE_Handle h)1456 sane_cancel (SANE_Handle h)
1457 {
1458   TScanner *s;
1459 
1460   DBG (DBG_MSG, "sane_cancel\n");
1461 
1462   s = (TScanner *) h;
1463   /* Make sure the scanner head returns home */
1464   FinishScan (&s->HWParams);
1465   /* delete allocated data */
1466   if (s->fScanning)
1467     {
1468       CircBufferExit (&s->DataPipe);
1469       free (s->DataPipe.pabLineBuf);
1470       s->DataPipe.pabLineBuf = NULL;
1471       DBG (DBG_MSG, "sane_cancel: freeing buffers\n");
1472     }
1473   s->fCancelled = SANE_TRUE;
1474   s->fScanning = SANE_FALSE;
1475 }
1476 
1477 
1478 SANE_Status
sane_set_io_mode(SANE_Handle __sane_unused__ h,SANE_Bool m)1479 sane_set_io_mode (SANE_Handle __sane_unused__ h, SANE_Bool m)
1480 {
1481   DBG (DBG_MSG, "sane_set_io_mode %s\n", m ? "non-blocking" : "blocking");
1482 
1483   if (m)
1484     {
1485       return SANE_STATUS_UNSUPPORTED;
1486     }
1487   return SANE_STATUS_GOOD;
1488 }
1489 
1490 
1491 SANE_Status
sane_get_select_fd(SANE_Handle __sane_unused__ h,SANE_Int __sane_unused__ * fd)1492 sane_get_select_fd (SANE_Handle __sane_unused__ h, SANE_Int __sane_unused__ * fd)
1493 {
1494   DBG (DBG_MSG, "sane_select_fd\n");
1495   return SANE_STATUS_UNSUPPORTED;
1496 }
1497