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