• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* sane - Scanner Access Now Easy.
2 
3    Copyright (C) 1997, 1998, 2002, 2013 Franck Schnefra, Michel Roelofs,
4    Emmanuel Blot, Mikko Tyolajarvi, David Mosberger-Tang, Wolfgang Goeller,
5    Petter Reinholdtsen, Gary Plewa, Sebastien Sable, Max Ushakov,
6    Andrew Goodbody, Oliver Schwartz and Kevin Charter
7 
8    This file is part of the SANE package.
9 
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2 of the
13    License, or (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <https://www.gnu.org/licenses/>.
22 
23    As a special exception, the authors of SANE give permission for
24    additional uses of the libraries contained in this release of SANE.
25 
26    The exception is that, if you link a SANE library with other files
27    to produce an executable, this does not by itself cause the
28    resulting executable to be covered by the GNU General Public
29    License.  Your use of that executable is in no way restricted on
30    account of linking the SANE library code into it.
31 
32    This exception does not, however, invalidate any other reasons why
33    the executable file might be covered by the GNU General Public
34    License.
35 
36    If you submit changes to SANE to the maintainers to be included in
37    a subsequent release, you agree by submitting the changes that
38    those changes may be distributed with this exception intact.
39 
40    If you write modifications of your own for SANE, it is your choice
41    whether to permit this exception to apply to your modifications.
42    If you do not wish that, delete this exception notice.
43 
44    This file is a component of the implementation of a backend for many
45    of the AGFA SnapScan and Acer Vuego/Prisa flatbed scanners.
46 */
47 
48 /*
49    SnapScan backend data sources (implementation)
50 */
51 
52 /**************************************************************************************
53 If you get confused from all the structs (like I did when I first saw them),
54 think of it as "C++ in C". If you're accustomed to OO and UML maybe the
55 following diagram helps you to make sense of it:
56 
57                        ------------------------
58                        !        Source        !
59                        ------------------------
60                        !pss: SnapScan_Scanner*!
61                        ------------------------   +psub
62                        !init() = 0            !-----------------
63                        !remaining() = 0       !                !
64                        !bytesPerLine()        !                !
65                        !pixelsPerLine()       !                !
66                        !get() = 0             !                !{TransformerSource forwards
67                        !done() = 0            !                ! function calls to corres-
68                        ------------------------                ! ponding functions in psub}
69                                    ^                           !
70                                   /_\                          !
71                                    !                           !
72        --------------------------------------------------     /\
73        !               !                !               !     \/
74 -------------    -------------    -------------    -------------------
75 !SCSISource !    ! FDSource  !    !BufSource  !    !TransformerSource!
76 =============    =============    =============    ===================
77 !remaining()!    !remaining()!    !remaining()!    !init()           !
78 !get()      !    !get()      !    !get()      !    !remaining()      !
79 !done()     !    !done()     !    !done()     !    !bytesPerLine()   !
80 !init()     !    !init()     !    !init()     !    !pixelsPerLine()  !
81 -------------    -------------    -------------    !get()            !
82                                                    !done()           !
83                                                    -------------------
84                                                             ^
85                                                            /_\
86                                                             !
87                                        ------------------------------------
88                                        !                 !                !
89                               ----------------    -------------    -------------
90                               !   Expander   !    ! RGBRouter !    !  Inverter !
91                               ================    =============    =============
92                               !remaining()   !    !remaining()!    !remaining()!
93                               !bytesPerLine()!    !get()      !    !get()      !
94                               !get()         !    !done()     !    !done()     !
95                               !done()        !    !init()     !    !init()     !
96                               !init()        !    -------------    -------------
97                               ----------------
98 All instances of the descendants of TransformerSource can be chained together. For
99 color scanning, a typical source chain would consist of an RGBRouter sitting on top
100 of a SCSISource. In the get() method, RGBRouter will then call the get() method of
101 the subsource, process the data and return it.
102 
103 I hope this makes sense to you (and I got the right idea of the original author's
104 intention).
105 ***********************************************************************************/
106 
Source_init(Source * pself,SnapScan_Scanner * pss,SourceRemaining remaining,SourceBytesPerLine bytesPerLine,SourcePixelsPerLine pixelsPerLine,SourceGet get,SourceDone done)107 static SANE_Status Source_init (Source *pself,
108                                 SnapScan_Scanner *pss,
109                                 SourceRemaining remaining,
110                                 SourceBytesPerLine bytesPerLine,
111                                 SourcePixelsPerLine pixelsPerLine,
112                                 SourceGet get,
113                                 SourceDone done)
114 {
115     pself->pss = pss;
116     pself->remaining = remaining;
117     pself->bytesPerLine = bytesPerLine;
118     pself->pixelsPerLine = pixelsPerLine;
119     pself->get = get;
120     pself->done = done;
121     return SANE_STATUS_GOOD;
122 }
123 
124 /* these are defaults, normally used only by base sources */
125 
Source_bytesPerLine(Source * pself)126 static SANE_Int Source_bytesPerLine (Source *pself)
127 {
128     return pself->pss->bytes_per_line;
129 }
130 
Source_pixelsPerLine(Source * pself)131 static SANE_Int Source_pixelsPerLine (Source *pself)
132 {
133     return pself->pss->pixels_per_line;
134 }
135 
136 /**********************************************************************/
137 
138 /* the base sources */
139 typedef enum
140 {
141     SCSI_SRC,
142     FD_SRC,
143     BUF_SRC
144 } BaseSourceType;
145 
146 
147 typedef struct
148 {
149     SOURCE_GUTS;
150     SANE_Int scsi_buf_pos;    /* current position in scsi buffer */
151     SANE_Int scsi_buf_max;    /* data limit */
152     SANE_Int absolute_max;    /* largest possible data read */
153 } SCSISource;
154 
SCSISource_remaining(Source * pself)155 static SANE_Int SCSISource_remaining (Source *pself)
156 {
157     SCSISource *ps = (SCSISource *) pself;
158     return ps->pss->bytes_remaining + (ps->scsi_buf_max - ps->scsi_buf_pos);
159 }
160 
SCSISource_get(Source * pself,SANE_Byte * pbuf,SANE_Int * plen)161 static SANE_Status SCSISource_get (Source *pself,
162                                    SANE_Byte *pbuf,
163                                    SANE_Int *plen)
164 {
165     SCSISource *ps = (SCSISource *) pself;
166     SANE_Status status = SANE_STATUS_GOOD;
167     SANE_Int remaining = *plen;
168     char* me = "SCSISource_get";
169 
170     DBG (DL_CALL_TRACE, "%s\n", me);
171     while (remaining > 0
172            && pself->remaining(pself) > 0
173            && status == SANE_STATUS_GOOD
174            && !cancelRead)
175     {
176         SANE_Int ndata = ps->scsi_buf_max - ps->scsi_buf_pos;
177         DBG (DL_DATA_TRACE, "%s: ndata %d; remaining %d\n", me, ndata, remaining);
178         if (ndata == 0)
179         {
180             ps->pss->expected_read_bytes = MIN((size_t)ps->absolute_max,
181                                            ps->pss->bytes_remaining);
182             ps->scsi_buf_pos = 0;
183             ps->scsi_buf_max = 0;
184             status = scsi_read (ps->pss, READ_IMAGE);
185             if (status != SANE_STATUS_GOOD)
186                 break;
187             ps->scsi_buf_max = ps->pss->read_bytes;
188             ndata = ps->pss->read_bytes;
189             ps->pss->bytes_remaining -= ps->pss->read_bytes;
190             DBG (DL_DATA_TRACE, "%s: pos: %d; max: %d; expected: %lu; read: %lu\n",
191                 me, ps->scsi_buf_pos, ps->scsi_buf_max, (u_long) ps->pss->expected_read_bytes,
192                 (u_long) ps->pss->read_bytes);
193         }
194         ndata = MIN(ndata, remaining);
195         memcpy (pbuf, ps->pss->buf + ps->scsi_buf_pos, (size_t)ndata);
196         pbuf += ndata;
197         ps->scsi_buf_pos += ndata;
198         remaining -= ndata;
199     }
200     *plen -= remaining;
201     return status;
202 }
203 
SCSISource_done(Source * pself)204 static SANE_Status SCSISource_done (Source *pself)
205 {
206     DBG(DL_MINOR_INFO, "SCSISource_done\n");
207     UNREFERENCED_PARAMETER(pself);
208     return SANE_STATUS_GOOD;
209 }
210 
SCSISource_init(SCSISource * pself,SnapScan_Scanner * pss)211 static SANE_Status SCSISource_init (SCSISource *pself, SnapScan_Scanner *pss)
212 {
213     SANE_Status status = Source_init ((Source *) pself, pss,
214                                       SCSISource_remaining,
215                                       Source_bytesPerLine,
216                                       Source_pixelsPerLine,
217                                       SCSISource_get,
218                                       SCSISource_done);
219     if (status == SANE_STATUS_GOOD)
220     {
221         pself->scsi_buf_max = 0;
222         pself->scsi_buf_pos = 0;
223         pself->absolute_max =
224             (pss->phys_buf_sz/pss->bytes_per_line)*pss->bytes_per_line;
225     }
226     return status;
227 }
228 
229 /* File sources */
230 
231 typedef struct
232 {
233     SOURCE_GUTS;
234     int fd;
235     SANE_Int bytes_remaining;
236 } FDSource;
237 
FDSource_remaining(Source * pself)238 static SANE_Int FDSource_remaining (Source *pself)
239 {
240     FDSource *ps = (FDSource *) pself;
241     return ps->bytes_remaining;
242 }
243 
FDSource_get(Source * pself,SANE_Byte * pbuf,SANE_Int * plen)244 static SANE_Status FDSource_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
245 {
246     SANE_Status status = SANE_STATUS_GOOD;
247     FDSource *ps = (FDSource *) pself;
248     SANE_Int remaining = *plen;
249 
250     while (remaining > 0
251            && pself->remaining(pself) > 0
252            && status == SANE_STATUS_GOOD)
253     {
254         SANE_Int bytes_read = read (ps->fd, pbuf, remaining);
255         if (bytes_read == -1)
256         {
257             if (errno == EAGAIN)
258             {
259                 /* No data currently available */
260                 break;
261             }
262             /* It's an IO error */
263             DBG (DL_MAJOR_ERROR, "%s: read failed: %s\n",
264                      __func__, strerror(errno));
265             status = SANE_STATUS_IO_ERROR;
266         }
267         else if (bytes_read == 0)
268         {
269             /* EOF of current reading */
270             DBG(DL_DATA_TRACE, "%s: EOF\n",__func__);
271             break;
272         }
273         ps->bytes_remaining -= bytes_read;
274         remaining -= bytes_read;
275         pbuf += bytes_read;
276     }
277     *plen -= remaining;
278     return status;
279 }
280 
FDSource_done(Source * pself)281 static SANE_Status FDSource_done (Source *pself)
282 {
283     close(((FDSource *) pself)->fd);
284     return SANE_STATUS_GOOD;
285 }
286 
FDSource_init(FDSource * pself,SnapScan_Scanner * pss,int fd)287 static SANE_Status FDSource_init (FDSource *pself,
288                                   SnapScan_Scanner *pss,
289                                   int fd)
290 {
291     SANE_Status status = Source_init ((Source *) pself,
292                                       pss,
293                                       FDSource_remaining,
294                                       Source_bytesPerLine,
295                                       Source_pixelsPerLine,
296                                       FDSource_get,
297                                       FDSource_done);
298     if (status == SANE_STATUS_GOOD)
299     {
300         pself->fd = fd;
301         pself->bytes_remaining = pss->bytes_per_line * (pss->lines + pss->chroma);
302     }
303     return status;
304 }
305 
306 
307 /* buffer sources simply read from a pre-filled buffer; we have these
308    so that we can include source chain processing overhead in the
309    measure_transfer_rate() function */
310 
311 typedef struct
312 {
313     SOURCE_GUTS;
314     SANE_Byte *buf;
315     SANE_Int buf_size;
316     SANE_Int buf_pos;
317 } BufSource;
318 
BufSource_remaining(Source * pself)319 static SANE_Int BufSource_remaining (Source *pself)
320 {
321     BufSource *ps = (BufSource *) pself;
322     return  ps->buf_size - ps->buf_pos;
323 }
324 
BufSource_get(Source * pself,SANE_Byte * pbuf,SANE_Int * plen)325 static SANE_Status BufSource_get (Source *pself,
326                                   SANE_Byte *pbuf,
327                                   SANE_Int *plen)
328 {
329     BufSource *ps = (BufSource *) pself;
330     SANE_Status status = SANE_STATUS_GOOD;
331     SANE_Int to_move = MIN(*plen, pself->remaining(pself));
332     if (to_move == 0)
333     {
334         status = SANE_STATUS_EOF;
335     }
336     else
337     {
338         memcpy (pbuf, ps->buf + ps->buf_pos, to_move);
339         ps->buf_pos += to_move;
340         *plen = to_move;
341     }
342     return status;
343 }
344 
BufSource_done(Source * pself)345 static SANE_Status BufSource_done (Source *pself)
346 {
347     UNREFERENCED_PARAMETER(pself);
348     return SANE_STATUS_GOOD;
349 }
350 
BufSource_init(BufSource * pself,SnapScan_Scanner * pss,SANE_Byte * buf,SANE_Int buf_size)351 static SANE_Status BufSource_init (BufSource *pself,
352                                    SnapScan_Scanner *pss,
353                                      SANE_Byte *buf,
354                                    SANE_Int buf_size)
355 {
356     SANE_Status status = Source_init ((Source *) pself,
357                                       pss,
358                                       BufSource_remaining,
359                                       Source_bytesPerLine,
360                                       Source_pixelsPerLine,
361                                       BufSource_get,
362                                       BufSource_done);
363     DBG(DL_DATA_TRACE, "BufSource_init: buf_size=%d\n", buf_size);
364     if (status == SANE_STATUS_GOOD)
365     {
366         pself->buf = buf;
367         pself->buf_size = buf_size;
368         pself->buf_pos = 0;
369     }
370     return status;
371 }
372 
373 /* base source creation */
374 
create_base_source(SnapScan_Scanner * pss,BaseSourceType st,Source ** pps)375 static SANE_Status create_base_source (SnapScan_Scanner *pss,
376                                        BaseSourceType st,
377                                        Source **pps)
378 {
379     SANE_Status status = SANE_STATUS_GOOD;
380     *pps = NULL;
381     switch (st)
382     {
383     case SCSI_SRC:
384         *pps = (Source *) malloc(sizeof(SCSISource));
385         if (*pps == NULL)
386         {
387             DBG (DL_MAJOR_ERROR, "failed to allocate SCSISource");
388             status = SANE_STATUS_NO_MEM;
389         }
390         else
391         {
392             status = SCSISource_init ((SCSISource *) *pps, pss);
393         }
394     break;
395     case FD_SRC:
396         *pps = (Source *) malloc(sizeof(FDSource));
397         if (*pps == NULL)
398         {
399             DBG (DL_MAJOR_ERROR, "failed to allocate FDSource");
400             status = SANE_STATUS_NO_MEM;
401         }
402         else
403         {
404             status = FDSource_init ((FDSource *) *pps, pss, pss->rpipe[0]);
405         }
406     break;
407     case BUF_SRC:
408         *pps = (Source *) malloc(sizeof(BufSource));
409         if (*pps == NULL)
410         {
411             DBG (DL_MAJOR_ERROR, "failed to allocate BufSource");
412             status = SANE_STATUS_NO_MEM;
413         }
414         else
415         {
416             status = BufSource_init ((BufSource *) *pps,
417                                      pss,
418                                      pss->buf,
419                                      pss->read_bytes);
420         }
421     break;
422     default:
423         DBG (DL_MAJOR_ERROR, "illegal base source type %d", st);
424         break;
425     }
426     return status;
427 }
428 
429 /**********************************************************************/
430 
431 /* The transformer sources */
432 
433 #define TX_SOURCE_GUTS \
434         SOURCE_GUTS;\
435         Source *psub    /* sub-source */
436 
437 typedef struct
438 {
439     TX_SOURCE_GUTS;
440 } TxSource;
441 
TxSource_remaining(Source * pself)442 static SANE_Int TxSource_remaining (Source *pself)
443 {
444     TxSource *ps = (TxSource *) pself;
445     return ps->psub->remaining(ps->psub);
446 }
447 
TxSource_bytesPerLine(Source * pself)448 static SANE_Int TxSource_bytesPerLine (Source *pself)
449 {
450     TxSource *ps = (TxSource *) pself;
451     return ps->psub->bytesPerLine(ps->psub);
452 }
453 
TxSource_pixelsPerLine(Source * pself)454 static SANE_Int TxSource_pixelsPerLine (Source *pself)
455 {
456     TxSource *ps = (TxSource *) pself;
457     return ps->psub->pixelsPerLine(ps->psub);
458 }
459 
TxSource_get(Source * pself,SANE_Byte * pbuf,SANE_Int * plen)460 static SANE_Status TxSource_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
461 {
462     TxSource *ps = (TxSource *) pself;
463     return ps->psub->get(ps->psub, pbuf, plen);
464 }
465 
TxSource_done(Source * pself)466 static SANE_Status TxSource_done (Source *pself)
467 {
468     TxSource *ps = (TxSource *) pself;
469     SANE_Status status = ps->psub->done(ps->psub);
470     free(ps->psub);
471     ps->psub = NULL;
472     return status;
473 }
474 
TxSource_init(TxSource * pself,SnapScan_Scanner * pss,SourceRemaining remaining,SourceBytesPerLine bytesPerLine,SourcePixelsPerLine pixelsPerLine,SourceGet get,SourceDone done,Source * psub)475 static SANE_Status TxSource_init (TxSource *pself,
476                                   SnapScan_Scanner *pss,
477                                   SourceRemaining remaining,
478                                   SourceBytesPerLine bytesPerLine,
479                                   SourcePixelsPerLine pixelsPerLine,
480                                   SourceGet get,
481                                   SourceDone done,
482                                   Source *psub)
483 {
484     SANE_Status status = Source_init((Source *) pself,
485                                      pss,
486                                      remaining,
487                                      bytesPerLine,
488                                      pixelsPerLine,
489                                      get,
490                                      done);
491     if (status == SANE_STATUS_GOOD)
492         pself->psub = psub;
493     return status;
494 }
495 
496 /* The expander makes three-channel, one-bit, raw scanner data into
497    8-bit data. It is used to support the bilevel colour scanning mode */
498 
499 typedef struct
500 {
501     TX_SOURCE_GUTS;
502     SANE_Byte *ch_buf;            /* channel buffer */
503     SANE_Int   ch_size;            /* channel buffer size = #bytes in a channel */
504     SANE_Int   ch_ndata;        /* actual #bytes in channel buffer */
505     SANE_Int   ch_pos;            /* position in buffer */
506     SANE_Int   bit;                /* current bit */
507     SANE_Int   last_bit;        /* current last bit (counting down) */
508     SANE_Int   last_last_bit;    /* last bit in the last byte of the channel */
509 } Expander;
510 
Expander_remaining(Source * pself)511 static SANE_Int Expander_remaining (Source *pself)
512 {
513     Expander *ps = (Expander *) pself;
514     SANE_Int sub_remaining = TxSource_remaining(pself);
515     SANE_Int sub_bits_per_channel = TxSource_pixelsPerLine(pself);
516     SANE_Int whole_channels = sub_remaining/ps->ch_size;
517     SANE_Int result = whole_channels*sub_bits_per_channel;
518 
519     if (ps->ch_pos < ps->ch_size)
520     {
521         SANE_Int bits_covered = MAX((ps->ch_pos - 1)*8, 0) + 7 - ps->bit;
522         result += sub_bits_per_channel - bits_covered;
523     }
524 
525     return result;
526 }
527 
Expander_bytesPerLine(Source * pself)528 static SANE_Int Expander_bytesPerLine (Source *pself)
529 {
530     return TxSource_pixelsPerLine(pself)*3;
531 }
532 
Expander_get(Source * pself,SANE_Byte * pbuf,SANE_Int * plen)533 static SANE_Status Expander_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
534 {
535     Expander *ps = (Expander *) pself;
536     SANE_Status status = SANE_STATUS_GOOD;
537     SANE_Int remaining = *plen;
538 
539     while (remaining > 0
540            &&
541            pself->remaining(pself) > 0 &&
542            !cancelRead)
543     {
544         if (ps->ch_pos == ps->ch_ndata)
545         {
546             /* we need more data; try to get the remainder of the current
547                channel, or else the next channel */
548             SANE_Int ndata = ps->ch_size - ps->ch_ndata;
549             if (ndata == 0)
550             {
551                 ps->ch_ndata = 0;
552                 ps->ch_pos = 0;
553                 ndata = ps->ch_size;
554             }
555             status = TxSource_get(pself, ps->ch_buf + ps->ch_pos, &ndata);
556             if (status != SANE_STATUS_GOOD)
557                 break;
558             if (ndata == 0)
559                 break;
560             ps->ch_ndata += ndata;
561             if (ps->ch_pos == (ps->ch_size - 1))
562                 ps->last_bit = ps->last_last_bit;
563             else
564                 ps->last_bit = 0;
565             ps->bit = 7;
566         }
567         *pbuf = ((ps->ch_buf[ps->ch_pos] >> ps->bit) & 0x01) ? 0xFF : 0x00;
568         pbuf++;
569         remaining--;
570 
571         if (ps->bit == ps->last_bit)
572         {
573             ps->bit = 7;
574             ps->ch_pos++;
575             if (ps->ch_pos == (ps->ch_size - 1))
576                 ps->last_bit = ps->last_last_bit;
577             else
578                 ps->last_bit = 0;
579         }
580         else
581         {
582             ps->bit--;
583         }
584     }
585 
586     *plen -= remaining;
587     return status;
588 }
589 
Expander_done(Source * pself)590 static SANE_Status Expander_done (Source *pself)
591 {
592     Expander *ps = (Expander *) pself;
593     SANE_Status status = TxSource_done(pself);
594     free(ps->ch_buf);
595     ps->ch_buf = NULL;
596     ps->ch_size = 0;
597     ps->ch_pos = 0;
598     return status;
599 }
600 
Expander_init(Expander * pself,SnapScan_Scanner * pss,Source * psub)601 static SANE_Status Expander_init (Expander *pself,
602                   SnapScan_Scanner *pss,
603                                   Source *psub)
604 {
605     SANE_Status status = TxSource_init((TxSource *) pself,
606                                        pss,
607                                        Expander_remaining,
608                                        Expander_bytesPerLine,
609                                        TxSource_pixelsPerLine,
610                                        Expander_get,
611                                        Expander_done,
612                                        psub);
613     if (status == SANE_STATUS_GOOD)
614     {
615         pself->ch_size = TxSource_bytesPerLine((Source *) pself)/3;
616         pself->ch_buf = (SANE_Byte *) malloc(pself->ch_size);
617         if (pself->ch_buf == NULL)
618         {
619             DBG (DL_MAJOR_ERROR,
620                  "%s: couldn't allocate channel buffer.\n",
621                  __func__);
622             status = SANE_STATUS_NO_MEM;
623         }
624         else
625         {
626             pself->ch_ndata = 0;
627             pself->ch_pos = 0;
628             pself->last_last_bit = pself->pixelsPerLine((Source *) pself)%8;
629             if (pself->last_last_bit == 0)
630                 pself->last_last_bit = 7;
631             pself->last_last_bit = 7 - pself->last_last_bit;
632             pself->bit = 7;
633             if (pself->ch_size > 1)
634                 pself->last_bit = 0;
635             else
636                 pself->last_bit = pself->last_last_bit;
637         }
638     }
639     return status;
640 }
641 
create_Expander(SnapScan_Scanner * pss,Source * psub,Source ** pps)642 static SANE_Status create_Expander (SnapScan_Scanner *pss,
643                                     Source *psub,
644                                     Source **pps)
645 {
646     SANE_Status status = SANE_STATUS_GOOD;
647     *pps = (Source *) malloc(sizeof(Expander));
648     if (*pps == NULL)
649     {
650         DBG (DL_MAJOR_ERROR,
651              "%s: failed to allocate Expander.\n",
652              __func__);
653         status = SANE_STATUS_NO_MEM;
654     }
655     else
656     {
657         status = Expander_init ((Expander *) *pps, pss, psub);
658     }
659     return status;
660 }
661 
662 /*
663    This filter implements a fix for scanners that have some columns
664    of pixels offset. Currently it only shifts every other column
665    starting with the first one down ch_offset pixels.
666 
667    The Deinterlacer detects if data is in SANE RGB frame format (3 bytes/pixel)
668    or in Grayscale (1 byte/pixel).
669 
670    The first ch_offset lines of data in the output are fudged so that even indexed
671    add odd indexed pixels will have the same value. This is necessary because
672    the real pixel values of the columns that are shifted down are not
673    in the data for the first ch_offset lines. A better way to handle this would be to
674    scan in ch_offset extra lines of data, but I haven't figured out how to do this
675    yet.
676 
677 */
678 
679 typedef struct
680 {
681     TX_SOURCE_GUTS;
682     SANE_Byte *ch_buf;            /* channel buffer */
683     SANE_Int   ch_size;           /* channel buffer size */
684     SANE_Int   ch_line_size;      /* size of one line */
685     SANE_Int   ch_ndata;          /* actual #bytes in channel buffer */
686     SANE_Int   ch_pos;            /* position in buffer */
687     SANE_Int   ch_bytes_per_pixel;
688     SANE_Bool  ch_lineart;
689     SANE_Int   ch_offset;         /* The number of lines to be shifted */
690     SANE_Bool  ch_past_init;      /* flag indicating if we have enough data to shift pixels down */
691     SANE_Bool  ch_shift_even;     /* flag indicating whether even or odd pixels are shifted */
692 } Deinterlacer;
693 
Deinterlacer_remaining(Source * pself)694 static SANE_Int Deinterlacer_remaining (Source *pself)
695 {
696     Deinterlacer *ps = (Deinterlacer *) pself;
697     SANE_Int result = TxSource_remaining(pself);
698     result += ps->ch_ndata - ps->ch_pos;
699     return result;
700 }
701 
Deinterlacer_get(Source * pself,SANE_Byte * pbuf,SANE_Int * plen)702 static SANE_Status Deinterlacer_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
703 {
704     Deinterlacer *ps = (Deinterlacer *) pself;
705     SANE_Status status = SANE_STATUS_GOOD;
706     SANE_Int remaining = *plen;
707     SANE_Int org_len = *plen;
708     char *me = "Deinterlacer_get";
709 
710     DBG(DL_DATA_TRACE, "%s: remaining=%d, pself->remaining=%d, ch_ndata=%d, ch_pos=%d\n",
711             me, remaining, pself->remaining(pself), ps->ch_ndata, ps->ch_pos);
712 
713     while (remaining > 0
714            &&
715            pself->remaining(pself) > 0 &&
716            !cancelRead)
717     {
718         if (ps->ch_pos % (ps->ch_line_size) == ps->ch_ndata % (ps->ch_line_size) )
719         {
720             /* we need more data; try to get the remainder of the current
721                line, or else the next line */
722             SANE_Int ndata = (ps->ch_line_size) - ps->ch_ndata % (ps->ch_line_size);
723             if (ps->ch_pos >= ps->ch_size)
724             {
725 	        /* wrap to the beginning of the buffer if we need to */
726                 ps->ch_ndata = 0;
727                 ps->ch_pos = 0;
728                 ndata = ps->ch_line_size;
729             }
730             status = TxSource_get(pself, ps->ch_buf + ps->ch_pos, &ndata);
731             if (status != SANE_STATUS_GOOD)
732                 break;
733             if (ndata == 0)
734                 break;
735             ps->ch_ndata += ndata;
736         }
737         /* Handle special lineart mode: Valid pixels need to be masked */
738         if (ps->ch_lineart)
739         {
740             if (ps->ch_past_init)
741             {
742                 if (ps->ch_shift_even)
743                 {
744                     /* Even columns need to be shifted, i.e. bits 1,3,5,7 -> 0xaa */
745                     /* use valid pixels from this line and shifted pixels from ch_size lines back */
746                     *pbuf = (ps->ch_buf[ps->ch_pos] & 0x55) |
747                             (ps->ch_buf[(ps->ch_pos + (ps->ch_line_size)) % ps->ch_size] & 0xaa);
748                 }
749                 else
750                 {
751                     /* Odd columns need to be shifted, i.e. bits 0,2,4,6 -> 0x55 */
752                     *pbuf = (ps->ch_buf[ps->ch_pos] & 0xaa) |
753                             (ps->ch_buf[(ps->ch_pos + (ps->ch_line_size)) % ps->ch_size] & 0x55);
754                 }
755             }
756             else
757             {
758                 /* not enough data. duplicate pixel values from previous column */
759                 if (ps->ch_shift_even)
760                 {
761                     /* bits 0,2,4,6 contain valid data -> 0x55 */
762                     SANE_Byte valid_pixel = ps->ch_buf[ps->ch_pos] & 0x55;
763                     *pbuf = valid_pixel | (valid_pixel >> 1);
764                 }
765                 else
766                 {
767 
768                     /* bits 1,3,5,7 contain valid data -> 0xaa */
769                     SANE_Byte valid_pixel = ps->ch_buf[ps->ch_pos] & 0xaa;
770                     *pbuf = valid_pixel | (valid_pixel << 1);
771                 }
772             }
773         }
774         else /* colour / grayscale mode */
775         {
776             if ((ps->ch_shift_even && ((ps->ch_pos/ps->ch_bytes_per_pixel) % 2 == 0)) ||
777                 (!ps->ch_shift_even && ((ps->ch_pos/ps->ch_bytes_per_pixel) % 2 == 1)))
778             {
779                 /* the even indexed pixels need to be shifted down */
780                 if (ps->ch_past_init){
781                     /* We need to use data 4 lines back */
782                     /* So we just go one forward and it will wrap around to 4 back. */
783                     *pbuf = ps->ch_buf[(ps->ch_pos + (ps->ch_line_size)) % ps->ch_size];
784                 }else{
785                     /* Use data from the next pixel for even indexed pixels
786                       if we are on the first few lines.
787                       TODO: also we will overread the buffer if the buffer read ended
788                       on the first pixel. */
789                     if (ps->ch_pos % (ps->ch_line_size) == 0 )
790                         *pbuf = ps->ch_buf[ps->ch_pos+ps->ch_bytes_per_pixel];
791                     else
792                         *pbuf = ps->ch_buf[ps->ch_pos-ps->ch_bytes_per_pixel];
793                 }
794             }else{
795                 /* odd indexed pixels are okay */
796                 *pbuf = ps->ch_buf[ps->ch_pos];
797             }
798         }
799 	/* set the flag so we know we have enough data to start shifting columns */
800 	if (ps->ch_pos >= ps->ch_line_size * ps->ch_offset)
801 	   ps->ch_past_init = SANE_TRUE;
802 
803         pbuf++;
804         remaining--;
805         ps->ch_pos++;
806     }
807 
808     *plen -= remaining;
809 
810     DBG(DL_DATA_TRACE,
811         "%s: Request=%d, remaining=%d, read=%d, TXSource_rem=%d, bytes_rem=%lu\n",
812         me,
813         org_len,
814         pself->remaining(pself),
815         *plen,
816         TxSource_remaining(pself),
817         (u_long) ps->pss->bytes_remaining);
818     return status;
819 }
820 
Deinterlacer_done(Source * pself)821 static SANE_Status Deinterlacer_done (Source *pself)
822 {
823     Deinterlacer *ps = (Deinterlacer *) pself;
824     SANE_Status status = TxSource_done(pself);
825     free(ps->ch_buf);
826     ps->ch_buf = NULL;
827     ps->ch_size = 0;
828     ps->ch_line_size = 0;
829     ps->ch_pos = 0;
830     return status;
831 }
832 
Deinterlacer_init(Deinterlacer * pself,SnapScan_Scanner * pss,Source * psub)833 static SANE_Status Deinterlacer_init (Deinterlacer *pself,
834                   SnapScan_Scanner *pss,
835                                   Source *psub)
836 {
837     SANE_Status status = TxSource_init((TxSource *) pself,
838                                        pss,
839                                        Deinterlacer_remaining,
840                                        TxSource_bytesPerLine,
841                                        TxSource_pixelsPerLine,
842                                        Deinterlacer_get,
843                                        Deinterlacer_done,
844                                        psub);
845     if (status == SANE_STATUS_GOOD)
846     {
847         pself->ch_shift_even = SANE_TRUE;
848         switch (pss->pdev->model)
849         {
850         case PERFECTION3490:
851             pself->ch_offset = 8;
852             if ((actual_mode(pss) == MD_GREYSCALE) || (actual_mode(pss) == MD_LINEART))
853                  pself->ch_shift_even = SANE_FALSE;
854             break;
855         case PERFECTION2480:
856         default:
857             pself->ch_offset = 4;
858             break;
859         }
860         pself->ch_line_size = TxSource_bytesPerLine((Source *) pself);
861         /* We need at least ch_offset+1 lines of buffer in order
862            to shift up ch_offset pixels. */
863         pself->ch_size = pself->ch_line_size * (pself->ch_offset + 1);
864         pself->ch_buf = (SANE_Byte *) malloc(pself->ch_size);
865         if (pself->ch_buf == NULL)
866         {
867             DBG (DL_MAJOR_ERROR,
868                  "%s: couldn't allocate channel buffer.\n",
869                  __func__);
870             status = SANE_STATUS_NO_MEM;
871         }
872         else
873         {
874             pself->ch_ndata = 0;
875             pself->ch_pos = 0;
876             pself->ch_past_init = SANE_FALSE;
877 	    if ((actual_mode(pss) == MD_GREYSCALE) || (actual_mode(pss) == MD_LINEART))
878 	    	pself->ch_bytes_per_pixel = 1;
879 	    else
880 	    	pself->ch_bytes_per_pixel = 3;
881 	    if (pss->bpp_scan == 16)
882 		pself->ch_bytes_per_pixel *= 2;
883         }
884         pself->ch_lineart = (actual_mode(pss) == MD_LINEART);
885     }
886     return status;
887 }
888 
create_Deinterlacer(SnapScan_Scanner * pss,Source * psub,Source ** pps)889 static SANE_Status create_Deinterlacer (SnapScan_Scanner *pss,
890                                     Source *psub,
891                                     Source **pps)
892 {
893     SANE_Status status = SANE_STATUS_GOOD;
894     *pps = (Source *) malloc(sizeof(Deinterlacer));
895     if (*pps == NULL)
896     {
897         DBG (DL_MAJOR_ERROR,
898              "%s: failed to allocate Deinterlacer.\n",
899              __func__);
900         status = SANE_STATUS_NO_MEM;
901     }
902     else
903     {
904         status = Deinterlacer_init ((Deinterlacer *) *pps, pss, psub);
905     }
906     return status;
907 }
908 
909 /* ----------------------------------------------------- */
910 
911 /* the RGB router assumes 8-bit RGB data arranged in contiguous
912    channels, possibly with R-G and R-B offsets, and rearranges the
913    data into SANE RGB frame format */
914 
915 typedef struct
916 {
917     TX_SOURCE_GUTS;
918     SANE_Byte *cbuf;            /* circular line buffer */
919     SANE_Byte *xbuf;            /* single line buffer */
920     SANE_Int pos;                    /* current position in xbuf */
921     SANE_Int cb_size;            /* size of the circular buffer */
922     SANE_Int cb_line_size;/* size of a line in the circular buffer */
923     SANE_Int cb_start;        /* start of valid data in the circular buffer */
924     SANE_Int cb_finish;        /* finish of valid data, for next read */
925     SANE_Int ch_offset[3];/* offset in cbuf */
926     SANE_Int round_req;
927     SANE_Int round_read;
928 } RGBRouter;
929 
put_int16r(int n,u_char * p)930 static void put_int16r (int n, u_char *p)
931 {
932 	p[0] = (n & 0x00ff);
933 	p[1] = (n & 0xff00) >> 8;
934 }
935 
936 
RGBRouter_remaining(Source * pself)937 static SANE_Int RGBRouter_remaining (Source *pself)
938 {
939     RGBRouter *ps = (RGBRouter *) pself;
940    SANE_Int remaining;
941     if (ps->round_req == ps->cb_size)
942         remaining = TxSource_remaining(pself) - ps->cb_size + ps->cb_line_size;
943     else
944       remaining = TxSource_remaining(pself) + ps->cb_line_size - ps->pos;
945    return (remaining);
946 }
947 
RGBRouter_get(Source * pself,SANE_Byte * pbuf,SANE_Int * plen)948 static SANE_Status RGBRouter_get (Source *pself,
949                                   SANE_Byte *pbuf,
950                                   SANE_Int *plen)
951 {
952     RGBRouter *ps = (RGBRouter *) pself;
953     SANE_Status status = SANE_STATUS_GOOD;
954     SANE_Int remaining = *plen;
955     SANE_Byte *s;
956     SANE_Int i, t;
957     SANE_Int r, g, b;
958     SANE_Int run_req;
959     SANE_Int org_len = *plen;
960     char *me = "RGBRouter_get";
961 
962     while (remaining > 0  &&  pself->remaining(pself) > 0 && !cancelRead)
963     {
964         DBG(DL_DATA_TRACE, "%s: remaining=%d, pself->remaining=%d, round_req=%d, cb_size=%d\n",
965             me, remaining, pself->remaining(pself), ps->round_req, ps->cb_size);
966         /* Check if there is no valid data left from previous get */
967         if (ps->pos >= ps->cb_line_size)
968         {
969             /* Try to get more data. either one line or
970                full buffer (first time) */
971             do
972             {
973                 run_req = ps->round_req - ps->round_read;
974                 status = TxSource_get (pself,
975                                        ps->cbuf + ps->cb_start + ps->round_read,
976                                        &run_req);
977                 if (status != SANE_STATUS_GOOD || run_req==0)
978                 {
979                     *plen -= remaining;
980                     if ( *plen > 0 )
981                         DBG(DL_DATA_TRACE, "%s: request=%d, read=%d\n",
982                             me, org_len, *plen);
983                     return status;
984                 }
985                 ps->round_read += run_req;
986             }
987             while ((ps->round_req > ps->round_read) && !cancelRead);
988 
989             /* route RGB */
990             ps->cb_start = (ps->cb_start + ps->round_read)%ps->cb_size;
991             s = ps->xbuf;
992             r = (ps->cb_start + ps->ch_offset[0])%ps->cb_size;
993             g = (ps->cb_start + ps->ch_offset[1])%ps->cb_size;
994             b = (ps->cb_start + ps->ch_offset[2])%ps->cb_size;
995             for (i = 0;  i < ps->cb_line_size/3;  i++)
996             {
997                 if (pself->pss->bpp_scan == 8)
998                 {
999                     *s++ = ps->cbuf[r++];
1000                     *s++ = ps->cbuf[g++];
1001                     *s++ = ps->cbuf[b++];
1002                 }
1003                 else if (pself->pss->pdev->model == SCANWIT2720S)
1004                 {
1005                     t = (((ps->cbuf[r+1] << 8) | ps->cbuf[r]) & 0xfff) << 4;
1006                     put_int16r (t, s);
1007                     s += 2;
1008                     r += 2;
1009                     t = (((ps->cbuf[g+1] << 8) | ps->cbuf[g]) & 0xfff) << 4;
1010                     put_int16r (t, s);
1011                     s += 2;
1012                     g += 2;
1013                     t = (((ps->cbuf[b+1] << 8) | ps->cbuf[b]) & 0xfff) << 4;
1014                     put_int16r (t, s);
1015                     s += 2;
1016                     b += 2;
1017                     i++;
1018                 }
1019                 else
1020                 {
1021                     *s++ = ps->cbuf[r++];
1022                     *s++ = ps->cbuf[r++];
1023                     *s++ = ps->cbuf[g++];
1024                     *s++ = ps->cbuf[g++];
1025                     *s++ = ps->cbuf[b++];
1026                     *s++ = ps->cbuf[b++];
1027                     i++;
1028                 }
1029             }
1030 
1031             /* end of reading & offsetiing whole line data;
1032                reset valid position */
1033             ps->pos = 0;
1034 
1035             /* prepare for next round */
1036             ps->round_req = ps->cb_line_size;
1037             ps->round_read =0;
1038         }
1039 
1040         /* Repack the whole scan line and copy to caller's buffer */
1041         while (remaining > 0  &&  ps->pos < ps->cb_line_size)
1042         {
1043             *pbuf++ = ps->xbuf[ps->pos++];
1044             remaining--;
1045         }
1046     }
1047     *plen -= remaining;
1048     DBG(DL_DATA_TRACE,
1049         "%s: Request=%d, remaining=%d, read=%d, TXSource_rem=%d, bytes_rem=%lu\n",
1050         me,
1051         org_len,
1052         pself->remaining(pself),
1053         *plen,
1054         TxSource_remaining(pself),
1055         (u_long) ps->pss->bytes_remaining);
1056     return status;
1057 }
1058 
RGBRouter_done(Source * pself)1059 static SANE_Status RGBRouter_done (Source *pself)
1060 {
1061     RGBRouter *ps = (RGBRouter *) pself;
1062     SANE_Status status = TxSource_done(pself);
1063 
1064     free(ps->cbuf);
1065     free(ps->xbuf);
1066     ps->cbuf = NULL;
1067     ps->cb_start = -1;
1068     ps->pos = 0;
1069     return status;
1070 }
1071 
RGBRouter_init(RGBRouter * pself,SnapScan_Scanner * pss,Source * psub)1072 static SANE_Status RGBRouter_init (RGBRouter *pself,
1073                            SnapScan_Scanner *pss,
1074                                    Source *psub)
1075 {
1076     SANE_Status status = TxSource_init((TxSource *) pself,
1077                                        pss,
1078                                        RGBRouter_remaining,
1079                                        TxSource_bytesPerLine,
1080                                        TxSource_pixelsPerLine,
1081                                        RGBRouter_get,
1082                                        RGBRouter_done,
1083                                        psub);
1084     if (status == SANE_STATUS_GOOD)
1085     {
1086         SANE_Int lines_in_buffer = 0;
1087 
1088         /* Size the buffer to accommodate the necessary number of scan
1089            lines to cater for the offset between R, G and B */
1090         lines_in_buffer = pss->chroma + 1;
1091         pself->cb_line_size = pself->bytesPerLine((Source *) pself);
1092         pself->cb_size = pself->cb_line_size*lines_in_buffer;
1093         pself->pos = pself->cb_line_size;
1094 
1095         pself->round_req = pself->cb_size;
1096         pself->round_read = 0;
1097 
1098         pself->cbuf = (SANE_Byte *) malloc(pself->cb_size);
1099         pself->xbuf = (SANE_Byte *) malloc(pself->cb_line_size);
1100         if (pself->cbuf == NULL  ||  pself->xbuf == NULL)
1101         {
1102             DBG (DL_MAJOR_ERROR,
1103                  "%s: failed to allocate circular buffer.\n",
1104                  __func__);
1105             status = SANE_STATUS_NO_MEM;
1106         }
1107         else
1108         {
1109             SANE_Int ch;
1110 
1111             pself->cb_start = 0;
1112             for (ch = 0;  ch < 3;  ch++)
1113             {
1114                 pself->ch_offset[ch] =
1115                         pss->chroma_offset[ch] * pself->cb_line_size
1116                         + ch * (pself->cb_line_size / 3);
1117             }
1118         }
1119         DBG(DL_MINOR_INFO, "RGBRouter_init: buf_size: %d x %d = %d\n",
1120             pself->cb_line_size, lines_in_buffer, pself->cb_size);
1121         DBG(DL_MINOR_INFO, "RGBRouter_init: buf offset R:%d G:%d B:%d\n",
1122             pself->ch_offset[0], pself->ch_offset[1],pself->ch_offset[2]);
1123     }
1124     return status;
1125 }
1126 
create_RGBRouter(SnapScan_Scanner * pss,Source * psub,Source ** pps)1127 static SANE_Status create_RGBRouter (SnapScan_Scanner *pss,
1128                                      Source *psub,
1129                                      Source **pps)
1130 {
1131     static char me[] = "create_RGBRouter";
1132     SANE_Status status = SANE_STATUS_GOOD;
1133 
1134     DBG (DL_CALL_TRACE, "%s\n", me);
1135     *pps = (Source *) malloc(sizeof(RGBRouter));
1136     if (*pps == NULL)
1137     {
1138         DBG (DL_MAJOR_ERROR, "%s: failed to allocate RGBRouter.\n",
1139              __func__);
1140         status = SANE_STATUS_NO_MEM;
1141     }
1142     else
1143     {
1144         status = RGBRouter_init ((RGBRouter *) *pps, pss, psub);
1145     }
1146     return status;
1147 }
1148 
1149 /* An Inverter is used to invert the bits in a lineart image */
1150 
1151 typedef struct
1152 {
1153     TX_SOURCE_GUTS;
1154 } Inverter;
1155 
Inverter_get(Source * pself,SANE_Byte * pbuf,SANE_Int * plen)1156 static SANE_Status Inverter_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
1157 {
1158     SANE_Status status = TxSource_get (pself, pbuf, plen);
1159     if (status == SANE_STATUS_GOOD)
1160     {
1161         int i;
1162         for (i = 0;  i < *plen;  i++)
1163             pbuf[i] ^= 0xFF;
1164     }
1165     return status;
1166 }
1167 
Inverter_init(Inverter * pself,SnapScan_Scanner * pss,Source * psub)1168 static SANE_Status Inverter_init (Inverter *pself,
1169                                   SnapScan_Scanner *pss,
1170                                   Source *psub)
1171 {
1172     return  TxSource_init ((TxSource *) pself,
1173                            pss,
1174                            TxSource_remaining,
1175                            TxSource_bytesPerLine,
1176                            TxSource_pixelsPerLine,
1177                            Inverter_get,
1178                            TxSource_done,
1179                            psub);
1180 }
1181 
create_Inverter(SnapScan_Scanner * pss,Source * psub,Source ** pps)1182 static SANE_Status create_Inverter (SnapScan_Scanner *pss,
1183                                     Source *psub,
1184                                     Source **pps)
1185 {
1186     SANE_Status status = SANE_STATUS_GOOD;
1187     *pps = (Source *) malloc(sizeof(Inverter));
1188     if (*pps == NULL)
1189     {
1190         DBG (DL_MAJOR_ERROR, "%s: failed to allocate Inverter.\n",
1191                  __func__);
1192         status = SANE_STATUS_NO_MEM;
1193     }
1194     else
1195     {
1196         status = Inverter_init ((Inverter *) *pps, pss, psub);
1197     }
1198     return status;
1199 }
1200 
1201 /* Source chain creation */
1202 
create_source_chain(SnapScan_Scanner * pss,BaseSourceType bst,Source ** pps)1203 static SANE_Status create_source_chain (SnapScan_Scanner *pss,
1204                                         BaseSourceType bst,
1205                                         Source **pps)
1206 {
1207    static char me[] = "create_source_chain";
1208     SANE_Status status = create_base_source (pss, bst, pps);
1209 
1210    DBG (DL_CALL_TRACE, "%s\n", me);
1211     if (status == SANE_STATUS_GOOD)
1212     {
1213         SnapScan_Mode mode = actual_mode(pss);
1214         switch (mode)
1215         {
1216         case MD_COLOUR:
1217             status = create_RGBRouter (pss, *pps, pps);
1218             /* We only have the interlace problems on
1219                some scanners like the Epson Perfection 2480/2580
1220                at 2400 dpi. */
1221             if (status == SANE_STATUS_GOOD &&
1222                 ((pss->pdev->model == PERFECTION2480 && pss->res == 2400) ||
1223                 (pss->pdev->model == PERFECTION3490 && pss->res == 3200) ||
1224                 (pss->pdev->model == PRISA5000E && pss->res == 1200)))
1225                 status = create_Deinterlacer (pss, *pps, pps);
1226             break;
1227         case MD_BILEVELCOLOUR:
1228             status = create_Expander (pss, *pps, pps);
1229             if (status == SANE_STATUS_GOOD)
1230                 status = create_RGBRouter (pss, *pps, pps);
1231             if (status == SANE_STATUS_GOOD &&
1232                 ((pss->pdev->model == PERFECTION2480 && pss->res == 2400) ||
1233                 (pss->pdev->model == PERFECTION3490 && pss->res == 3200) ||
1234                 (pss->pdev->model == PRISA5000E && pss->res == 1200)))
1235                 status = create_Deinterlacer (pss, *pps, pps);
1236             break;
1237         case MD_GREYSCALE:
1238             if ((pss->pdev->model == PERFECTION2480 && pss->res == 2400) ||
1239                 (pss->pdev->model == PERFECTION3490 && pss->res == 3200) ||
1240                 (pss->pdev->model == PRISA5000E && pss->res == 1200))
1241                 status = create_Deinterlacer (pss, *pps, pps);
1242             break;
1243         case MD_LINEART:
1244             /* The SnapScan creates a negative image by
1245                default... so for the user interface to make sense,
1246                the internal meaning of "negative" is reversed */
1247             if (pss->negative == SANE_FALSE)
1248                 status = create_Inverter (pss, *pps, pps);
1249             if (pss->pdev->model == PERFECTION3490 && pss->res == 3200)
1250                 status = create_Deinterlacer (pss, *pps, pps);
1251             break;
1252         default:
1253             DBG (DL_MAJOR_ERROR, "%s: bad mode value %d (internal error)\n",
1254                  __func__, mode);
1255             status = SANE_STATUS_INVAL;
1256             break;
1257         }
1258     }
1259     return status;
1260 }
1261 
1262 /*
1263  * Revision 1.21  2005/12/02 19:12:54  oliver-guest
1264  * Another fix for lineart mode for the Epson 3490 @ 3200 DPI
1265  *
1266  * Revision 1.20  2005/11/28 19:28:29  oliver-guest
1267  * Fix for lineart mode of Epson 3490 @ 3200 DPI
1268  *
1269  * Revision 1.19  2005/11/25 17:24:48  oliver-guest
1270  * Fix for Epson 3490 @ 3200 DPI for grayscale and lineart mode
1271  *
1272  * Revision 1.18  2005/11/17 23:47:11  oliver-guest
1273  * Revert previous 'fix', disable 2400 dpi for Epson 3490, use 1600 dpi instead
1274  *
1275  * Revision 1.17  2005/11/17 23:32:23  oliver-guest
1276  * Fixes for Epson 3490 @ 2400 DPI
1277  *
1278  * Revision 1.16  2005/11/10 19:42:02  oliver-guest
1279  * Added deinterlacing for Epson 3490
1280  *
1281  * Revision 1.15  2005/10/31 21:08:47  oliver-guest
1282  * Distinguish between Benq 5000/5000E/5000U
1283  *
1284  * Revision 1.14  2005/10/13 22:43:30  oliver-guest
1285  * Fixes for 16 bit scan mode from Simon Munton
1286  *
1287  * Revision 1.13  2005/10/11 18:47:07  oliver-guest
1288  * Fixes for Epson 3490 and 16 bit scan mode
1289  *
1290  * Revision 1.12  2004/11/14 19:26:38  oliver-guest
1291  * Applied patch from Julien Blache to change ch_past_init from SANE_Int to SANE_Bool
1292  *
1293  * Revision 1.11  2004/11/09 23:17:38  oliver-guest
1294  * First implementation of deinterlacer for Epson scanners at high resolutions (thanks to Brad Johnson)
1295  *
1296  * Revision 1.10  2004/10/03 17:34:36  hmg-guest
1297  * 64 bit platform fixes (bug #300799).
1298  *
1299  * Revision 1.9  2004/04/09 16:18:37  oliver-guest
1300  * Fix initialization of FDSource.bytes_remaining
1301  *
1302  * Revision 1.8  2004/04/09 11:59:02  oliver-guest
1303  * Fixes for pthread implementation
1304  *
1305  * Revision 1.7  2004/04/08 21:53:10  oliver-guest
1306  * Use sanei_thread in snapscan backend
1307  *
1308  * Revision 1.6  2001/12/17 22:51:49  oliverschwartz
1309  * Update to snapscan-20011212 (snapscan 1.4.3)
1310  *
1311  * Revision 1.18  2001/12/12 19:44:59  oliverschwartz
1312  * Clean up CVS log
1313  *
1314  * Revision 1.17  2001/11/27 23:16:17  oliverschwartz
1315  * - Fix color alignment for SnapScan 600
1316  * - Added documentation in snapscan-sources.c
1317  * - Guard against TL_X < BR_X and TL_Y < BR_Y
1318  *
1319  * Revision 1.16  2001/10/08 18:22:02  oliverschwartz
1320  * - Disable quality calibration for Acer Vuego 310F
1321  * - Use sanei_scsi_max_request_size as scanner buffer size
1322  *   for SCSI devices
1323  * - Added new devices to snapscan.desc
1324  *
1325  * Revision 1.15  2001/09/28 15:56:51  oliverschwartz
1326  * - fix hanging for SNAPSCAN300 / VUEGO 310
1327  *
1328  * Revision 1.14  2001/09/28 13:39:16  oliverschwartz
1329  * - Added "Snapscan 300" ID string
1330  * - cleanup
1331  * - more debugging messages in snapscan-sources.c
1332  *
1333  * Revision 1.13  2001/09/18 15:01:07  oliverschwartz
1334  * - Read scanner id string again after firmware upload
1335  *   to identify correct model
1336  * - Make firmware upload work for AGFA scanners
1337  * - Change copyright notice
1338  *
1339  * Revision 1.12  2001/09/09 18:06:32  oliverschwartz
1340  * add changes from Acer (new models; automatic firmware upload for USB scanners); fix distorted colour scans after greyscale scans (call set_window only in sane_start); code cleanup
1341  *
1342  * Revision 1.11  2001/04/13 13:12:18  oliverschwartz
1343  * use absolute_max as expected_read_bytes for PRISA620S
1344  *
1345  * Revision 1.10  2001/04/10 11:04:31  sable
1346  * Adding support for snapscan e40 an e50 thanks to Giuseppe Tanzilli
1347  *
1348  * Revision 1.9  2001/03/17 22:53:21  sable
1349  * Applying Mikael Magnusson patch concerning Gamma correction
1350  * Support for 1212U_2
1351  *
1352  * Revision 1.8  2000/11/28 03:55:07  cbagwell
1353  * Reverting a fix to RGBRouter_remaining to original fix.  This allows
1354  * most scanners to scan at 600 dpi by ignoring insufficient data in
1355  * the RGB circular buffer and always returning size = 1 in those cases.
1356  * This should probably be fixed at a higher level.
1357  *
1358  * Revision 1.7  2000/11/20 01:02:42  cbagwell
1359  * Updates so that USB will continue reading when it receives an EAGAIN error.
1360  * Also, changed RGBRouter_remaining to not be able to return a negative
1361  * value.
1362  *
1363  * Revision 1.6  2000/11/04 01:53:58  cbagwell
1364  * Committing some needed USB updates.  Added extra test logic to detect
1365  * bad bytes_expected values.  Just to help debug faster on scanners
1366  * that tickle the bug.
1367  *
1368  * Revision 1.5  2000/10/30 22:32:20  sable
1369  * Support for vuego310s vuego610s and 1236s
1370  *
1371  * Revision 1.4  2000/10/28 14:16:10  sable
1372  * Bug correction for SnapScan310
1373  *
1374  * Revision 1.3  2000/10/28 14:06:35  sable
1375  * Add support for Acer300f
1376  *
1377  * Revision 1.2  2000/10/13 03:50:27  cbagwell
1378  * Updating to source from SANE 1.0.3.  Calling this version 1.1
1379  * */
1380