1 /* sane - Scanner Access Now Easy.
2    Copyright (C) 1996 David Mosberger-Tang
3    Copyright (C) 1997 R.E.Wolff@BitWizard.nl
4    This file is part of the SANE package.
5 
6    This program is free software; you can redistribute it and/or
7    modify it under the terms of the GNU General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <https://www.gnu.org/licenses/>.
18 
19    Note: The exception that is mentioned in the other source files is
20    not here. If a case arises where you need the rights that that
21    exception gives you, Please do contact me, and we'll work something
22    out.
23 
24    R.E.Wolff@BitWizard.nl
25    tel: +31-152137555
26    fax: +31-152138217
27 
28    This file implements a SANE backend for Tamarack flatbed scanners.  */
29 
30 /*
31    This driver was written initially by changing all occurrences of
32    "mustek" to "tamarack". This actually worked without modification
33    for the manufacturer detection code! :-)
34 
35  */
36 
37 
38 #include "../include/sane/config.h"
39 
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <limits.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <sys/types.h>
48 #include <unistd.h>
49 #include <sys/time.h>
50 
51 #include "../include/_stdint.h"
52 
53 #include "../include/sane/sane.h"
54 #include "../include/sane/sanei.h"
55 #include "../include/sane/saneopts.h"
56 #include "../include/sane/sanei_scsi.h"
57 #include "../include/sane/sanei_thread.h"
58 #include "../include/sane/sanei_config.h"
59 
60 /* For timeval... */
61 #ifdef DEBUG
62 #include <sys/time.h>
63 #endif
64 
65 
66 #define BACKEND_NAME	tamarack
67 #include "../include/sane/sanei_backend.h"
68 
69 #include "tamarack.h"
70 
71 #ifndef PATH_MAX
72 # define PATH_MAX	1024
73 #endif
74 
75 #define TAMARACK_CONFIG_FILE "tamarack.conf"
76 
77 
78 static const SANE_Device **devlist = NULL;
79 static int num_devices;
80 static Tamarack_Device *first_dev;
81 static Tamarack_Scanner *first_handle;
82 
83 static const SANE_String_Const mode_list[] =
84   {
85     SANE_VALUE_SCAN_MODE_LINEART,
86     SANE_VALUE_SCAN_MODE_HALFTONE,
87     SANE_VALUE_SCAN_MODE_GRAY,
88     SANE_VALUE_SCAN_MODE_COLOR,
89     0
90   };
91 
92 
93 #if 0
94 static const SANE_Range u8_range =
95   {
96       0,				/* minimum */
97     255,				/* maximum */
98       0				/* quantization */
99   };
100 #endif
101 
102 
103 /* David used " 100 << SANE_FIXED_SCALE_SHIFT ". This assumes that
104  * it is implemented that way. I want to hide the datatype.
105  */
106 static const SANE_Range percentage_range =
107   {
108     SANE_FIX(-100),	/* minimum */
109     SANE_FIX( 100),	/* maximum */
110     SANE_FIX( 1  )	/* quantization */
111   };
112 
113 /* David used " 100 << SANE_FIXED_SCALE_SHIFT ". This assumes that
114  * it is implemented that way. I want to hide the datatype.
115  */
116 static const SANE_Range abs_percentage_range =
117   {
118     SANE_FIX( 0),	/* minimum */
119     SANE_FIX( 100),	/* maximum */
120     SANE_FIX( 1  )	/* quantization */
121   };
122 
123 
124 #define INQ_LEN	0x60
125 static const uint8_t inquiry[] =
126 {
127   TAMARACK_SCSI_INQUIRY, 0x00, 0x00, 0x00, INQ_LEN, 0x00
128 };
129 
130 static const uint8_t test_unit_ready[] =
131 {
132   TAMARACK_SCSI_TEST_UNIT_READY, 0x00, 0x00, 0x00, 0x00, 0x00
133 };
134 
135 static const uint8_t stop[] =
136 {
137   TAMARACK_SCSI_START_STOP, 0x00, 0x00, 0x00, 0x00, 0x00
138 };
139 
140 static const uint8_t get_status[] =
141 {
142   TAMARACK_SCSI_GET_DATA_STATUS, 0x00, 0x00, 0x00, 0x00, 0x00,
143                                        0x00, 0x00, 0x0c, 0x00
144 };
145 
146 
147 
148 static SANE_Status
wait_ready(int fd)149 wait_ready (int fd)
150 {
151   SANE_Status status;
152   int i;
153 
154   for (i = 0; i < 1000; ++i)
155     {
156       DBG(3, "wait_ready: sending TEST_UNIT_READY\n");
157       status = sanei_scsi_cmd (fd, test_unit_ready, sizeof (test_unit_ready),
158 			       0, 0);
159       switch (status)
160 	{
161 	default:
162 	  /* Ignore errors while waiting for scanner to become ready.
163 	     Some SCSI drivers return EIO while the scanner is
164 	     returning to the home position.  */
165 	  DBG(1, "wait_ready: test unit ready failed (%s)\n",
166 	      sane_strstatus (status));
167 	  /* fall through */
168 	case SANE_STATUS_DEVICE_BUSY:
169 	  usleep (100000);	/* retry after 100ms */
170 	  break;
171 
172 	case SANE_STATUS_GOOD:
173 	  return status;
174 	}
175     }
176   DBG(1, "wait_ready: timed out after %d attempts\n", i);
177   return SANE_STATUS_INVAL;
178 }
179 
180 
181 
182 static SANE_Status
sense_handler(int scsi_fd, u_char *result, void *arg)183 sense_handler (int scsi_fd, u_char *result, void *arg)
184 {
185   (void) scsi_fd;
186   (void) arg; /* silence compilation warnings */
187 
188   switch (result[0])
189     {
190     case 0x00:
191       break;
192 
193     default:
194       DBG(1, "sense_handler: got unknown sense code %02x\n", result[0]);
195       return SANE_STATUS_IO_ERROR;
196     }
197   return SANE_STATUS_GOOD;
198 }
199 
200 
201 /* XXX This might leak the memory to a TAMARACK string */
202 
203 static SANE_Status
attach(const char *devname, Tamarack_Device **devp)204 attach (const char *devname, Tamarack_Device **devp)
205 {
206   char result[INQ_LEN];
207   int fd;
208   Tamarack_Device *dev;
209   SANE_Status status;
210   size_t size;
211   char *mfg, *model;
212   char *p;
213 
214   for (dev = first_dev; dev; dev = dev->next)
215     if (strcmp (dev->sane.name, devname) == 0) {
216       if (devp)
217 	*devp = dev;
218       return SANE_STATUS_GOOD;
219     }
220 
221   DBG(3, "attach: opening %s\n", devname);
222   status = sanei_scsi_open (devname, &fd, sense_handler, 0);
223   if (status != SANE_STATUS_GOOD) {
224     DBG(1, "attach: open failed (%s)\n", sane_strstatus (status));
225     return SANE_STATUS_INVAL;
226   }
227 
228   DBG(3, "attach: sending INQUIRY\n");
229   size = sizeof (result);
230   status = sanei_scsi_cmd (fd, inquiry, sizeof (inquiry), result, &size);
231   if (status != SANE_STATUS_GOOD || size != INQ_LEN) {
232     DBG(1, "attach: inquiry failed (%s)\n", sane_strstatus (status));
233     sanei_scsi_close (fd);
234     return status;
235   }
236 
237   status = wait_ready (fd);
238   sanei_scsi_close (fd);
239   if (status != SANE_STATUS_GOOD)
240     return status;
241 
242   result[33]= '\0';
243   p = strchr(result+16,' ');
244   if (p) *p = '\0';
245   model = strdup (result+16);
246 
247   result[16]= '\0';
248   p = strchr(result+8,' ');
249   if (p) *p = '\0';
250   mfg = strdup (result+8);
251 
252   DBG(1, "attach: Inquiry gives mfg=%s, model=%s.\n", mfg, model);
253 
254   if (strcmp (mfg, "TAMARACK") != 0) {
255     DBG(1, "attach: device doesn't look like a Tamarack scanner "
256 	   "(result[0]=%#02x)\n", result[0]);
257     return SANE_STATUS_INVAL;
258   }
259 
260   dev = malloc (sizeof (*dev));
261   if (!dev)
262     return SANE_STATUS_NO_MEM;
263 
264   memset (dev, 0, sizeof (*dev));
265 
266   dev->sane.name   = strdup (devname);
267   dev->sane.vendor = "Tamarack";
268   dev->sane.model  = model;
269   dev->sane.type   = "flatbed scanner";
270 
271   dev->x_range.min = 0;
272   dev->y_range.min = 0;
273   dev->x_range.quant = 0;
274   dev->y_range.quant = 0;
275   dev->dpi_range.min = SANE_FIX (1);
276   dev->dpi_range.quant = SANE_FIX (1);
277 
278   dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH);
279   dev->y_range.max = SANE_FIX (11.0 * MM_PER_INCH);
280   dev->dpi_range.max = SANE_FIX (600);
281 
282   DBG(3, "attach: found Tamarack scanner model %s (%s)\n",
283       dev->sane.model, dev->sane.type);
284 
285   ++num_devices;
286   dev->next = first_dev;
287   first_dev = dev;
288 
289   if (devp)
290     *devp = dev;
291   return SANE_STATUS_GOOD;
292 }
293 
294 
295 static size_t
max_string_size(const SANE_String_Const strings[])296 max_string_size (const SANE_String_Const strings[])
297 {
298   size_t size, max_size = 0;
299   int i;
300 
301   for (i = 0; strings[i]; ++i)
302     {
303       size = strlen (strings[i]) + 1;
304       if (size > max_size)
305 	max_size = size;
306     }
307   return max_size;
308 }
309 
310 
311 static SANE_Status
constrain_value(Tamarack_Scanner *s, SANE_Int option, void *value, SANE_Int *info)312 constrain_value (Tamarack_Scanner *s, SANE_Int option, void *value,
313 		 SANE_Int *info)
314 {
315   return sanei_constrain_value (s->opt + option, value, info);
316 }
317 
318 
sign_mag(double val)319 static unsigned char sign_mag (double val)
320 {
321   if (val >  100) val =  100;
322   if (val < -100) val = -100;
323   if (val >= 0) return ( val);
324   else          return ((unsigned char)(-val)) | 0x80;
325 }
326 
327 
328 
329 static SANE_Status
scan_area_and_windows(Tamarack_Scanner *s)330 scan_area_and_windows (Tamarack_Scanner *s)
331 {
332   struct def_win_par dwp;
333 
334   memset (&dwp,'\0',sizeof (dwp));
335   dwp.dwph.opc = TAMARACK_SCSI_AREA_AND_WINDOWS;
336   set_triple (dwp.dwph.len,8 + sizeof (dwp.wdb));
337 
338   set_double (dwp.wdh.wpll, sizeof (dwp.wdb));
339 
340   dwp.wdb.winid = WINID;
341   set_double (dwp.wdb.xres, (int) SANE_UNFIX (s->val[OPT_RESOLUTION].w));
342   set_double (dwp.wdb.yres, (int) SANE_UNFIX (s->val[OPT_RESOLUTION].w));
343 
344   set_quad (dwp.wdb.ulx, (int) (47.2 * SANE_UNFIX (s->val[OPT_TL_X].w)));
345   set_quad (dwp.wdb.uly, (int) (47.2 * SANE_UNFIX (s->val[OPT_TL_Y].w)));
346   set_quad (dwp.wdb.width,
347      (int) (47.2 * SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w)));
348   set_quad (dwp.wdb.length,
349      (int) (47.2 * SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w)));
350 
351   dwp.wdb.brightness = sign_mag (SANE_UNFIX (s->val[OPT_BRIGHTNESS].w));
352   dwp.wdb.contrast   = sign_mag (SANE_UNFIX (s->val[OPT_CONTRAST].w));
353   dwp.wdb.thresh     = 0x80;
354 
355 
356   switch (s->mode) {
357   case THRESHOLDED:
358     dwp.wdb.bpp = 1;
359     dwp.wdb.image_comp = 0;
360     dwp.wdb.thresh     = 1 + 2.55 * (SANE_UNFIX (s->val[OPT_THRESHOLD].w));
361     break;
362   case DITHERED:
363     dwp.wdb.bpp = 1;
364     dwp.wdb.image_comp = 1;
365     break;
366   case GREYSCALE:
367     dwp.wdb.bpp = 8;
368     dwp.wdb.image_comp = 2;
369     break;
370   case TRUECOLOR:
371     dwp.wdb.bpp = 8;
372     dwp.wdb.image_comp = 2;
373     break;
374   default:
375     DBG(1, "Invalid mode. %d\n", s->mode);
376     return SANE_STATUS_INVAL;
377   }
378   DBG(1, "bright, thresh, contrast = %d(%5.1f), %d, %d(%5.1f)\n",
379       dwp.wdb.brightness, SANE_UNFIX (s->val[OPT_BRIGHTNESS].w),
380       dwp.wdb.thresh    ,
381       dwp.wdb.contrast  , SANE_UNFIX (s->val[OPT_CONTRAST].w));
382 
383   set_double (dwp.wdb.halftone, 1); /* XXX What does this do again ? */
384   dwp.wdb.pad_type   = 3;           /* This is the only usable pad-type. */
385   dwp.wdb.exposure   = 0x6f;        /* XXX Option? */
386   dwp.wdb.compr_type = 0;
387 
388   /* XXX Shouldn't this be sizeof (dwp) */
389   return sanei_scsi_cmd (s->fd, &dwp, (10+8+38), 0, 0);
390 }
391 
392 
393 static SANE_Status
mode_select(Tamarack_Scanner *s)394 mode_select (Tamarack_Scanner *s)
395 {
396   struct  {
397     struct command_header cmd;
398     struct page_header hdr;
399     struct tamarack_page page;
400   } c;
401 
402   memset (&c, '\0', sizeof (c));
403   c.cmd.opc = TAMARACK_SCSI_MODE_SELECT;
404   c.cmd.pad0[0] = 0x10;    /* Suddenly the pad bytes are no long pad... */
405   c.cmd.pad0[1] = 0;
406   c.cmd.len = sizeof (struct page_header) + sizeof (struct tamarack_page);
407   c.hdr.code = 0;
408   c.hdr.length = 6;
409   c.page.gamma = 2;
410   c.page.thresh = 0x80;    /* XXX Option? */
411   switch (s->mode) {
412   case THRESHOLDED:
413   case DITHERED:
414   case GREYSCALE:
415     c.page.masks = 0x80;
416     break;
417   case TRUECOLOR:
418     c.page.masks = 0x40 >> s->pass;
419     break;
420   }
421   c.page.delay = 0x10;      /* XXX Option? */
422   c.page.features = (s->val[OPT_TRANS].w ? TAM_TRANS_ON:0) | 1;
423   return sanei_scsi_cmd (s->fd, &c, sizeof (c), 0, 0);
424 }
425 
426 
427 static SANE_Status
start_scan(Tamarack_Scanner *s)428 start_scan (Tamarack_Scanner *s)
429 {
430   struct  {
431     struct command_header cmd;
432     unsigned char winid[1];
433   } c;
434 
435   memset (&c,'\0',sizeof (c));
436   c.cmd.opc = TAMARACK_SCSI_START_STOP;
437   c.cmd.len = sizeof (c.winid);
438   c.winid[0] = WINID;
439   return sanei_scsi_cmd (s->fd, &c, sizeof (c), 0, 0);
440 }
441 
442 
443 static SANE_Status
stop_scan(Tamarack_Scanner *s)444 stop_scan (Tamarack_Scanner *s)
445 {
446   /* XXX I don't think a TAMARACK can stop in mid-scan. Just stop
447      sending it requests for data....
448    */
449   return sanei_scsi_cmd (s->fd, stop, sizeof (stop), 0, 0);
450 }
451 
452 
453 static SANE_Status
do_eof(Tamarack_Scanner *s)454 do_eof (Tamarack_Scanner *s)
455 {
456   if (s->pipe >= 0)
457     {
458       close (s->pipe);
459       s->pipe = -1;
460     }
461   return SANE_STATUS_EOF;
462 }
463 
464 
465 static SANE_Status
do_cancel(Tamarack_Scanner *s)466 do_cancel (Tamarack_Scanner *s)
467 {
468   s->scanning = SANE_FALSE;
469   s->pass = 0;
470 
471   do_eof (s);
472 
473   if (sanei_thread_is_valid (s->reader_pid))
474     {
475       int exit_status;
476 
477       /* ensure child knows it's time to stop: */
478       sanei_thread_kill (s->reader_pid);
479       sanei_thread_waitpid (s->reader_pid, &exit_status);
480       sanei_thread_invalidate (s->reader_pid);
481     }
482 
483   if (s->fd >= 0)
484     {
485       stop_scan (s);
486       sanei_scsi_close (s->fd);
487       s->fd = -1;
488     }
489 
490   return SANE_STATUS_CANCELLED;
491 }
492 
493 
494 static SANE_Status
get_image_status(Tamarack_Scanner *s)495 get_image_status (Tamarack_Scanner *s)
496 {
497   uint8_t result[12];
498   SANE_Status status;
499   size_t len;
500   int busy;
501 
502 #if 1
503   do
504     {
505       len = sizeof (result);
506       status = sanei_scsi_cmd (s->fd, get_status, sizeof (get_status),
507 			    result, &len);
508       if ((status != SANE_STATUS_GOOD) && (status != SANE_STATUS_DEVICE_BUSY))
509 	return status;
510 
511       busy = (result[2] != 8) || (status == SANE_STATUS_DEVICE_BUSY);
512       if (busy)
513 	usleep (100000);
514 
515       if (!s->scanning)
516 	return do_cancel (s);
517     }
518   while (busy);
519 #else
520   /* XXX Test if this works one day... */
521   wait_ready (s);
522 #endif
523 
524   len = sizeof (result);
525   status = sanei_scsi_cmd (s->fd, get_status, sizeof (get_status),
526 			   result, &len);
527   if ((status != SANE_STATUS_GOOD) && (status != SANE_STATUS_DEVICE_BUSY))
528     return status;
529 
530   s->params.bytes_per_line =
531     result[ 8] | (result[ 7] << 8) | (result[6] << 16);
532   s->params.lines =
533     result[11] | (result[10] << 8) | (result[9] << 16);
534 
535   switch (s->mode) {
536   case DITHERED:
537   case THRESHOLDED:
538     s->params.pixels_per_line = 8 * s->params.bytes_per_line;
539     break;
540   case GREYSCALE:
541   case TRUECOLOR:
542     s->params.pixels_per_line =     s->params.bytes_per_line;
543     break;
544   }
545 
546 
547   DBG(1, "get_image_status: bytes_per_line=%d, lines=%d\n",
548       s->params.bytes_per_line, s->params.lines);
549   return SANE_STATUS_GOOD;
550 }
551 
552 
553 static SANE_Status
read_data(Tamarack_Scanner *s, SANE_Byte *buf, int lines, int bpl)554 read_data (Tamarack_Scanner *s, SANE_Byte *buf, int lines, int bpl)
555 {
556   struct command_header_10 cmd;
557   size_t nbytes;
558   SANE_Status status;
559 #ifdef DEBUG
560   int dt;
561   struct timeval tv_start,tv_end;
562 #endif
563 
564   nbytes = bpl * lines;
565   memset (&cmd,'\0',sizeof (cmd));
566   cmd.opc = 0x28;
567   set_triple (cmd.len,nbytes);
568 
569 #ifdef DEBUG
570   if (verbose) DBG (1, "Doing read_data... \n");
571   gettimeofday (&tv_start,NULL);
572 #endif
573 
574   status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), buf, &nbytes);
575 
576 #ifdef DEBUG
577   gettimeofday (&tv_end,NULL);
578   dt =  tv_end.tv_usec - tv_start.tv_usec +
579        (tv_end.tv_sec  - tv_start.tv_sec) * 1000000;
580   if (verbose) DBG(1, "Read took %d.%06d seconds.",
581 		   dt/1000000,dt%1000000);
582   dt = 1000000 * nbytes / dt;
583   if (verbose) DBG(1, "which is %d.%03d bytes per second.\n",dt,0);
584 #endif
585   return status;
586 }
587 
588 
589 
590 static SANE_Status
init_options(Tamarack_Scanner *s)591 init_options (Tamarack_Scanner *s)
592 {
593   int i;
594 
595   memset (s->opt, 0, sizeof (s->opt));
596   memset (s->val, 0, sizeof (s->val));
597 
598   for (i = 0; i < NUM_OPTIONS; ++i) {
599     s->opt[i].size = sizeof (SANE_Word);
600     s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
601   }
602 
603   s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
604   s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
605   s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
606   s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
607   s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
608 
609   /* "Mode" group: */
610   s->opt[OPT_MODE_GROUP].title = "Scan Mode";
611   s->opt[OPT_MODE_GROUP].desc = "";
612   s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
613   s->opt[OPT_MODE_GROUP].cap = 0;
614   s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
615 
616   /* scan mode */
617   s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
618   s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
619   s->opt[OPT_MODE].desc = "Select the scan mode";
620   s->opt[OPT_MODE].type = SANE_TYPE_STRING;
621   s->opt[OPT_MODE].size = max_string_size (mode_list);
622   s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
623   s->opt[OPT_MODE].constraint.string_list = mode_list;
624   s->val[OPT_MODE].s = strdup (mode_list[OPT_MODE_DEFAULT]);
625 
626   /* resolution */
627   s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
628   s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
629   s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
630   s->opt[OPT_RESOLUTION].type = SANE_TYPE_FIXED;
631   s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
632   s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
633   s->opt[OPT_RESOLUTION].constraint.range = &s->hw->dpi_range;
634   s->val[OPT_RESOLUTION].w = SANE_FIX (OPT_RESOLUTION_DEFAULT);
635 
636   /* preview */
637   s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
638   s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
639   s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
640   s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
641   s->val[OPT_PREVIEW].w = 0;
642 
643   /* gray preview */
644   s->opt[OPT_GRAY_PREVIEW].name = SANE_NAME_GRAY_PREVIEW;
645   s->opt[OPT_GRAY_PREVIEW].title = SANE_TITLE_GRAY_PREVIEW;
646   s->opt[OPT_GRAY_PREVIEW].desc = SANE_DESC_GRAY_PREVIEW;
647   s->opt[OPT_GRAY_PREVIEW].type = SANE_TYPE_BOOL;
648   s->val[OPT_GRAY_PREVIEW].w = SANE_FALSE;
649 
650   /* "Geometry" group: */
651   s->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
652   s->opt[OPT_GEOMETRY_GROUP].desc = "";
653   s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
654   s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
655   s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
656 
657   /* top-left x */
658   s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
659   s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
660   s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
661   s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
662   s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
663   s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
664   s->opt[OPT_TL_X].constraint.range = &s->hw->x_range;
665   s->val[OPT_TL_X].w = 0;
666 
667   /* top-left y */
668   s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
669   s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
670   s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
671   s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
672   s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
673   s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
674   s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range;
675   s->val[OPT_TL_Y].w = 0;
676 
677   /* bottom-right x */
678   s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
679   s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
680   s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
681   s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
682   s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
683   s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
684   s->opt[OPT_BR_X].constraint.range = &s->hw->x_range;
685   s->val[OPT_BR_X].w = s->hw->x_range.max;
686 
687   /* bottom-right y */
688   s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
689   s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
690   s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
691   s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
692   s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
693   s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
694   s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range;
695   s->val[OPT_BR_Y].w = s->hw->y_range.max;
696 
697   /* "Enhancement" group: */
698   s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
699   s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
700   s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
701   s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
702   s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
703 
704   /* transparency adapter. */
705   s->opt[OPT_TRANS].name = "transparency";
706   s->opt[OPT_TRANS].title = "transparency";
707   s->opt[OPT_TRANS].desc = "Turn on the transparency adapter.";
708   s->opt[OPT_TRANS].type = SANE_TYPE_BOOL;
709   s->opt[OPT_TRANS].unit = SANE_UNIT_NONE;
710   s->val[OPT_TRANS].w = SANE_FALSE;
711 
712   /* brightness */
713   s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
714   s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
715   s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS
716     "  This option is active for lineart/halftone modes only.  "
717     "For multibit modes (grey/color) use the gamma-table(s).";
718   s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_FIXED;
719   s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_PERCENT;
720   s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
721   s->opt[OPT_BRIGHTNESS].constraint.range = &percentage_range;
722   s->val[OPT_BRIGHTNESS].w = SANE_FIX(0);
723 
724   /* contrast */
725   s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
726   s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
727   s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST
728     "  This option is active for lineart/halftone modes only.  "
729     "For multibit modes (grey/color) use the gamma-table(s).";
730   s->opt[OPT_CONTRAST].type = SANE_TYPE_FIXED;
731   s->opt[OPT_CONTRAST].unit = SANE_UNIT_PERCENT;
732   s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
733   s->opt[OPT_CONTRAST].constraint.range = &percentage_range;
734   s->val[OPT_CONTRAST].w = SANE_FIX(0);
735 
736   /* Threshold */
737   s->opt[OPT_THRESHOLD].name = "Threshold";
738   s->opt[OPT_THRESHOLD].title = "Threshold";
739   s->opt[OPT_THRESHOLD].desc = "Threshold: below this level is black, above is white"
740     "  This option is active for bitmap modes only.  ";
741   s->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED;
742   s->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT;
743   s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
744   s->opt[OPT_THRESHOLD].constraint.range = &abs_percentage_range;
745   s->val[OPT_THRESHOLD].w = SANE_FIX(50);
746   s->opt[OPT_THRESHOLD].cap  |= SANE_CAP_INACTIVE;
747 
748 #if 0
749   /* custom-gamma table */
750   s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
751   s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
752   s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
753   s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
754   s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
755   s->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
756 
757   /* grayscale gamma vector */
758   s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
759   s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
760   s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
761   s->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
762   s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
763   s->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
764   s->opt[OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word);
765   s->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
766   s->opt[OPT_GAMMA_VECTOR].constraint.range = &u8_range;
767   s->val[OPT_GAMMA_VECTOR].wa = &s->gamma_table[0][0];
768 
769   /* red gamma vector */
770   s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
771   s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
772   s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
773   s->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
774   s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
775   s->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
776   s->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word);
777   s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
778   s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range;
779   s->val[OPT_GAMMA_VECTOR_R].wa = &s->gamma_table[1][0];
780 
781   /* green gamma vector */
782   s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
783   s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
784   s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
785   s->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
786   s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
787   s->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
788   s->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word);
789   s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
790   s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range;
791   s->val[OPT_GAMMA_VECTOR_G].wa = &s->gamma_table[2][0];
792 
793   /* blue gamma vector */
794   s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
795   s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
796   s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
797   s->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
798   s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
799   s->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
800   s->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word);
801   s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
802   s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range;
803   s->val[OPT_GAMMA_VECTOR_B].wa = &s->gamma_table[3][0];
804 #endif
805   return SANE_STATUS_GOOD;
806 }
807 
808 
809 /* This function is executed as a child process.  The reason this is
810    executed as a subprocess is because some (most?) generic SCSI
811    interfaces block a SCSI request until it has completed.  With a
812    subprocess, we can let it block waiting for the request to finish
813    while the main process can go about to do more important things
814    (such as recognizing when the user presses a cancel button).
815 
816    WARNING: Since this is executed as a subprocess, it's NOT possible
817    to update any of the variables in the main process (in particular
818    the scanner state cannot be updated).  */
819 static int
reader_process(void *scanner)820 reader_process (void *scanner)
821 {
822   Tamarack_Scanner *s = (Tamarack_Scanner *) scanner;
823   int fd = s->reader_pipe;
824 
825   SANE_Byte *data;
826   int lines_per_buffer, bpl;
827   SANE_Status status;
828   sigset_t sigterm_set;
829   sigset_t ignore_set;
830   struct SIGACTION act;
831   FILE *fp;
832 
833   if (sanei_thread_is_forked()) close (s->pipe);
834 
835   sigfillset (&ignore_set);
836   sigdelset (&ignore_set, SIGTERM);
837 #if defined (__APPLE__) && defined (__MACH__)
838   sigdelset (&ignore_set, SIGUSR2);
839 #endif
840   sigprocmask (SIG_SETMASK, &ignore_set, 0);
841 
842   memset (&act, 0, sizeof (act));
843   sigaction (SIGTERM, &act, 0);
844 
845   sigemptyset (&sigterm_set);
846   sigaddset (&sigterm_set, SIGTERM);
847 
848   fp = fdopen (fd, "w");
849   if (!fp)
850     return 1;
851 
852   bpl = s->params.bytes_per_line;
853 
854   lines_per_buffer = sanei_scsi_max_request_size / bpl;
855   if (!lines_per_buffer)
856     return 2;			/* resolution is too high */
857 
858   /* Limit the size of a single transfer to one inch.
859      XXX Add a stripsize option. */
860   if (lines_per_buffer > SANE_UNFIX (s->val[OPT_RESOLUTION].w))
861       lines_per_buffer = SANE_UNFIX (s->val[OPT_RESOLUTION].w);
862 
863   DBG(3, "lines_per_buffer=%d, bytes_per_line=%d\n", lines_per_buffer, bpl);
864 
865   data = malloc (lines_per_buffer * bpl);
866 
867   for (s->line = 0; s->line < s->params.lines; s->line += lines_per_buffer) {
868     if (s->line + lines_per_buffer > s->params.lines)
869       /* do the last few lines: */
870       lines_per_buffer = s->params.lines - s->line;
871 
872     sigprocmask (SIG_BLOCK, &sigterm_set, 0);
873     status = read_data (s, data, lines_per_buffer, bpl);
874     sigprocmask (SIG_UNBLOCK, &sigterm_set, 0);
875     if (status != SANE_STATUS_GOOD) {
876       DBG(1, "reader_process: read_data failed with status=%d\n", status);
877       return 3;
878     }
879     DBG(3, "reader_process: read %d lines\n", lines_per_buffer);
880 
881     if ((s->mode == TRUECOLOR) || (s->mode == GREYSCALE)) {
882       fwrite (data, lines_per_buffer, bpl, fp);
883     } else {
884       /* in singlebit mode, the scanner returns 1 for black. ;-( --DM */
885       /* Hah! Same for Tamarack... -- REW */
886       int i;
887 
888       for (i = 0; i < lines_per_buffer * bpl; ++i)
889 	fputc (~data[i], fp);
890     }
891   }
892   fclose (fp);
893   return 0;
894 }
895 
896 
897 static SANE_Status
attach_one(const char *dev)898 attach_one (const char *dev)
899 {
900   attach (dev, 0);
901   return SANE_STATUS_GOOD;
902 }
903 
904 
905 SANE_Status
sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize)906 sane_init (SANE_Int *version_code, SANE_Auth_Callback authorize)
907 {
908   char dev_name[PATH_MAX];
909   size_t len;
910   FILE *fp;
911 
912   (void) authorize; /* silence compilation warnings */
913 
914   DBG_INIT();
915 
916   sanei_thread_init();
917 
918   if (version_code)
919     *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
920 
921   fp = sanei_config_open (TAMARACK_CONFIG_FILE);
922   if (!fp) {
923     /* default to /dev/scanner instead of insisting on config file */
924     attach ("/dev/scanner", 0);
925     return SANE_STATUS_GOOD;
926   }
927 
928   while (sanei_config_read (dev_name, sizeof (dev_name), fp)) {
929     if (dev_name[0] == '#')		/* ignore line comments */
930       continue;
931     len = strlen (dev_name);
932 
933     if (!len)
934       continue;			/* ignore empty lines */
935 
936     sanei_config_attach_matching_devices (dev_name, attach_one);
937   }
938   fclose (fp);
939   return SANE_STATUS_GOOD;
940 }
941 
942 
943 void
sane_exit(void)944 sane_exit (void)
945 {
946   Tamarack_Device *dev, *next;
947 
948   for (dev = first_dev; dev; dev = next) {
949     next = dev->next;
950     free ((void *) dev->sane.name);
951     free ((void *) dev->sane.model);
952     free (dev);
953   }
954 
955   if (devlist)
956     free (devlist);
957 }
958 
959 SANE_Status
sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)960 sane_get_devices (const SANE_Device ***device_list, SANE_Bool local_only)
961 {
962   Tamarack_Device *dev;
963   int i;
964 
965   (void) local_only; /* silence compilation warnings */
966 
967   if (devlist)
968     free (devlist);
969 
970   devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
971   if (!devlist)
972     return SANE_STATUS_NO_MEM;
973 
974   i = 0;
975   for (dev = first_dev; i < num_devices; dev = dev->next)
976     devlist[i++] = &dev->sane;
977   devlist[i++] = 0;
978 
979   *device_list = devlist;
980   return SANE_STATUS_GOOD;
981 }
982 
983 
984 SANE_Status
sane_open(SANE_String_Const devicename, SANE_Handle *handle)985 sane_open (SANE_String_Const devicename, SANE_Handle *handle)
986 {
987   Tamarack_Device *dev;
988   SANE_Status status;
989   Tamarack_Scanner *s;
990   int i, j;
991 
992   if (devicename[0]) {
993     for (dev = first_dev; dev; dev = dev->next)
994       if (strcmp (dev->sane.name, devicename) == 0)
995 	break;
996 
997     if (!dev) {
998       status = attach (devicename, &dev);
999       if (status != SANE_STATUS_GOOD)
1000 	return status;
1001     }
1002   } else {
1003     /* empty devicname -> use first device */
1004     dev = first_dev;
1005   }
1006 
1007   if (!dev)
1008     return SANE_STATUS_INVAL;
1009 
1010   s = malloc (sizeof (*s));
1011   if (!s)
1012     return SANE_STATUS_NO_MEM;
1013   memset (s, 0, sizeof (*s));
1014   s->fd = -1;
1015   s->pipe = -1;
1016   s->hw = dev;
1017   for (i = 0; i < 4; ++i)
1018     for (j = 0; j < 256; ++j)
1019       s->gamma_table[i][j] = j;
1020 
1021   init_options (s);
1022 
1023   /* insert newly opened handle into list of open handles: */
1024   s->next = first_handle;
1025   first_handle = s;
1026 
1027   *handle = s;
1028   return SANE_STATUS_GOOD;
1029 }
1030 
1031 
1032 void
sane_close(SANE_Handle handle)1033 sane_close (SANE_Handle handle)
1034 {
1035   Tamarack_Scanner *prev, *s;
1036 
1037   /* remove handle from list of open handles: */
1038   prev = 0;
1039   for (s = first_handle; s; s = s->next) {
1040     if (s == handle)
1041       break;
1042     prev = s;
1043   }
1044 
1045   if (!s) {
1046     DBG(1, "close: invalid handle %p\n", handle);
1047     return;		/* oops, not a handle we know about */
1048   }
1049 
1050   if (s->scanning)
1051     do_cancel (handle);
1052 
1053   if (prev)
1054     prev->next = s->next;
1055   else
1056     first_handle = s->next;
1057 
1058   free (handle);
1059 }
1060 
1061 
1062 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle, SANE_Int option)1063 sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
1064 {
1065   Tamarack_Scanner *s = handle;
1066 
1067   if ((unsigned) option >= NUM_OPTIONS)
1068     return 0;
1069   return s->opt + option;
1070 }
1071 
1072 
1073 
make_mode(char *mode)1074 static int make_mode (char *mode)
1075 {
1076     if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0)
1077       return THRESHOLDED;
1078     if (strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0)
1079       return DITHERED;
1080     else if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1081       return GREYSCALE;
1082     else if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1083       return TRUECOLOR;
1084 
1085     return -1;
1086 }
1087 
1088 
1089 SANE_Status
sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *val, SANE_Int *info)1090 sane_control_option (SANE_Handle handle, SANE_Int option,
1091 		     SANE_Action action, void *val, SANE_Int *info)
1092 {
1093   Tamarack_Scanner *s = handle;
1094   SANE_Status status;
1095   SANE_Word cap;
1096 
1097   if (info)
1098     *info = 0;
1099 
1100   if (s->scanning)
1101     return SANE_STATUS_DEVICE_BUSY;
1102 
1103   if (option >= NUM_OPTIONS)
1104     return SANE_STATUS_INVAL;
1105 
1106   cap = s->opt[option].cap;
1107 
1108   if (!SANE_OPTION_IS_ACTIVE (cap))
1109     return SANE_STATUS_INVAL;
1110 
1111   if (action == SANE_ACTION_GET_VALUE) {
1112     switch (option) {
1113       /* word options: */
1114     case OPT_PREVIEW:
1115     case OPT_GRAY_PREVIEW:
1116     case OPT_RESOLUTION:
1117     case OPT_TL_X:
1118     case OPT_TL_Y:
1119     case OPT_BR_X:
1120     case OPT_BR_Y:
1121     case OPT_NUM_OPTS:
1122     case OPT_TRANS:
1123     case OPT_BRIGHTNESS:
1124     case OPT_CONTRAST:
1125     case OPT_THRESHOLD:
1126 #if 0
1127     case OPT_CUSTOM_GAMMA:
1128 #endif
1129       *(SANE_Word *) val = s->val[option].w;
1130       return SANE_STATUS_GOOD;
1131 
1132 #if 0
1133       /* word-array options: */
1134     case OPT_GAMMA_VECTOR:
1135     case OPT_GAMMA_VECTOR_R:
1136     case OPT_GAMMA_VECTOR_G:
1137     case OPT_GAMMA_VECTOR_B:
1138       memcpy (val, s->val[option].wa, s->opt[option].size);
1139       return SANE_STATUS_GOOD;
1140 #endif
1141 
1142       /* string options: */
1143     case OPT_MODE:
1144       strcpy (val, s->val[option].s);
1145       return SANE_STATUS_GOOD;
1146     }
1147   } else if (action == SANE_ACTION_SET_VALUE) {
1148     if (!SANE_OPTION_IS_SETTABLE (cap))
1149       return SANE_STATUS_INVAL;
1150 
1151     status = constrain_value (s, option, val, info);
1152     if (status != SANE_STATUS_GOOD)
1153       return status;
1154 
1155     switch (option)
1156       {
1157 	/* (mostly) side-effect-free word options: */
1158       case OPT_RESOLUTION:
1159       case OPT_TL_X:
1160       case OPT_TL_Y:
1161       case OPT_BR_X:
1162       case OPT_BR_Y:
1163 	if (info)
1164 	  *info |= SANE_INFO_RELOAD_PARAMS;
1165 	/* fall through */
1166       case OPT_PREVIEW:
1167       case OPT_GRAY_PREVIEW:
1168       case OPT_BRIGHTNESS:
1169       case OPT_CONTRAST:
1170       case OPT_THRESHOLD:
1171       case OPT_TRANS:
1172 	s->val[option].w = *(SANE_Word *) val;
1173 	return SANE_STATUS_GOOD;
1174 
1175 #if 0
1176 	/* side-effect-free word-array options: */
1177       case OPT_GAMMA_VECTOR:
1178       case OPT_GAMMA_VECTOR_R:
1179       case OPT_GAMMA_VECTOR_G:
1180       case OPT_GAMMA_VECTOR_B:
1181 	memcpy (s->val[option].wa, val, s->opt[option].size);
1182 	return SANE_STATUS_GOOD;
1183 
1184 	/* options with side-effects: */
1185 
1186       case OPT_CUSTOM_GAMMA:
1187 	w = *(SANE_Word *) val;
1188 	if (w == s->val[OPT_CUSTOM_GAMMA].w)
1189 	  return SANE_STATUS_GOOD;		/* no change */
1190 
1191 	s->val[OPT_CUSTOM_GAMMA].w = w;
1192 	if (w) {
1193 	  s->mode = make_mode (s->val[OPT_MODE].s);
1194 
1195 	  if (s->mode == GREYSCALE) {
1196 	    s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1197 	  } else if (s->mode == TRUECOLOR) {
1198 	    s->opt[OPT_GAMMA_VECTOR].cap   &= ~SANE_CAP_INACTIVE;
1199 	    s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1200 	    s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1201 	    s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1202 	  }
1203 	} else {
1204 	  s->opt[OPT_GAMMA_VECTOR].cap   |= SANE_CAP_INACTIVE;
1205 	  s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1206 	  s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1207 	  s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1208 	}
1209 	if (info)
1210 	  *info |= SANE_INFO_RELOAD_OPTIONS;
1211 	return SANE_STATUS_GOOD;
1212 #endif
1213 
1214       case OPT_MODE:
1215 	{
1216 
1217 	  if (s->val[option].s)
1218 	    free (s->val[option].s);
1219 	  s->val[option].s = strdup (val);
1220 
1221 	  s->mode = make_mode (s->val[OPT_MODE].s);
1222 
1223 	  if (info)
1224 	    *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1225 
1226 	  s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
1227 	  s->opt[OPT_CONTRAST].cap   |= SANE_CAP_INACTIVE;
1228 	  s->opt[OPT_THRESHOLD].cap  |= SANE_CAP_INACTIVE;
1229 #if 0
1230 	  s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1231 	  s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1232 	  s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1233 	  s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1234 	  s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1235 #endif
1236 
1237 
1238 	  if (strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0)
1239 	    s->opt[OPT_THRESHOLD].cap  &= ~SANE_CAP_INACTIVE;
1240 	  else {
1241 	    s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
1242 	    s->opt[OPT_CONTRAST].cap   &= ~SANE_CAP_INACTIVE;
1243 	  }
1244 #if 0
1245 	  if (!binary)
1246 	    s->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1247 
1248 	  if (s->val[OPT_CUSTOM_GAMMA].w) {
1249 	    if (strcmp (val, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1250 	      s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1251 	    else if (strcmp (val, SANE_VALUE_SCAN_MODE_COLOR) == 0) {
1252 	      s->opt[OPT_GAMMA_VECTOR].cap   &= ~SANE_CAP_INACTIVE;
1253 	      s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1254 	      s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1255 	      s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1256 	    }
1257 	  }
1258 #endif
1259 	  return SANE_STATUS_GOOD;
1260 	}
1261       }
1262     }
1263   return SANE_STATUS_INVAL;
1264 }
1265 
1266 
1267 SANE_Status
sane_get_parameters(SANE_Handle handle, SANE_Parameters *params)1268 sane_get_parameters (SANE_Handle handle, SANE_Parameters *params)
1269 {
1270   Tamarack_Scanner *s = handle;
1271 
1272   if (!s->scanning) {
1273     double width, height, dpi;
1274 
1275 
1276     memset (&s->params, 0, sizeof (s->params));
1277 
1278     width  = SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w);
1279     height = SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w);
1280     dpi    = SANE_UNFIX (s->val[OPT_RESOLUTION].w);
1281     s->mode = make_mode (s->val[OPT_MODE].s);
1282     DBG(1, "got mode '%s' -> %d.\n", s->val[OPT_MODE].s, s->mode);
1283     /* make best-effort guess at what parameters will look like once
1284        scanning starts.  */
1285     if (dpi > 0.0 && width > 0.0 && height > 0.0) {
1286       double dots_per_mm = dpi / MM_PER_INCH;
1287 
1288       s->params.pixels_per_line = width * dots_per_mm;
1289       s->params.lines = height * dots_per_mm;
1290     }
1291     if ((s->mode == THRESHOLDED) || (s->mode == DITHERED)) {
1292       s->params.format = SANE_FRAME_GRAY;
1293       s->params.bytes_per_line = (s->params.pixels_per_line + 7) / 8;
1294       s->params.depth = 1;
1295     } else if (s->mode == GREYSCALE) {
1296       s->params.format = SANE_FRAME_GRAY;
1297       s->params.bytes_per_line = s->params.pixels_per_line;
1298       s->params.depth = 8;
1299     } else {
1300       s->params.format = SANE_FRAME_RED + s->pass;
1301       s->params.bytes_per_line = s->params.pixels_per_line;
1302       s->params.depth = 8;
1303     }
1304     s->pass = 0;
1305   } else {
1306     if (s->mode == TRUECOLOR)
1307       s->params.format = SANE_FRAME_RED + s->pass;
1308   }
1309 
1310   s->params.last_frame =  (s->mode != TRUECOLOR) || (s->pass == 2);
1311 
1312   if (params)
1313     *params = s->params;
1314 
1315   DBG(1, "Got parameters: format:%d, ppl: %d, bpl:%d, depth:%d, "
1316 	   "last %d pass %d\n",
1317 	   s->params.format, s->params.pixels_per_line,
1318 	   s->params.bytes_per_line, s->params.depth,
1319 	   s->params.last_frame, s->pass);
1320   return SANE_STATUS_GOOD;
1321 }
1322 
1323 
1324 SANE_Status
sane_start(SANE_Handle handle)1325 sane_start (SANE_Handle handle)
1326 {
1327   Tamarack_Scanner *s = handle;
1328   SANE_Status status;
1329   int fds[2];
1330 
1331   /* First make sure we have a current parameter set.  Some of the
1332      parameters will be overwritten below, but that's OK.  */
1333   status = sane_get_parameters (s, 0);
1334 
1335   if (status != SANE_STATUS_GOOD)
1336       return status;
1337 
1338   if (s->fd < 0) {
1339     /* translate options into s->mode for convenient access: */
1340     s->mode = make_mode (s->val[OPT_MODE].s);
1341 
1342     if (s->mode == TRUECOLOR)
1343       {
1344 	if (s->val[OPT_PREVIEW].w && s->val[OPT_GRAY_PREVIEW].w) {
1345 	  /* Force gray-scale mode when previewing.  */
1346 	  s->mode = GREYSCALE;
1347 	  s->params.format = SANE_FRAME_GRAY;
1348 	  s->params.bytes_per_line = s->params.pixels_per_line;
1349 	  s->params.last_frame = SANE_TRUE;
1350 	}
1351       }
1352 
1353     status = sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, 0);
1354     if (status != SANE_STATUS_GOOD) {
1355       DBG(1, "open: open of %s failed: %s\n",
1356 	  s->hw->sane.name, sane_strstatus (status));
1357       return status;
1358     }
1359   }
1360 
1361   status = wait_ready (s->fd);
1362   if (status != SANE_STATUS_GOOD) {
1363     DBG(1, "open: wait_ready() failed: %s\n", sane_strstatus (status));
1364     goto stop_scanner_and_return;
1365   }
1366 
1367   status = scan_area_and_windows (s);
1368   if (status != SANE_STATUS_GOOD) {
1369     DBG(1, "open: set scan area command failed: %s\n",
1370 	sane_strstatus (status));
1371     goto stop_scanner_and_return;
1372   }
1373 
1374   status = mode_select (s);
1375   if (status != SANE_STATUS_GOOD)
1376     goto stop_scanner_and_return;
1377 
1378   s->scanning = SANE_TRUE;
1379 
1380   status = start_scan (s);
1381   if (status != SANE_STATUS_GOOD)
1382     goto stop_scanner_and_return;
1383 
1384   status = get_image_status (s);
1385   if (status != SANE_STATUS_GOOD)
1386     goto stop_scanner_and_return;
1387 
1388   s->line = 0;
1389 
1390   if (pipe (fds) < 0)
1391     return SANE_STATUS_IO_ERROR;
1392 
1393   s->pipe = fds[0];
1394   s->reader_pipe = fds[1];
1395   s->reader_pid = sanei_thread_begin (reader_process, (void *) s);
1396 
1397   if (sanei_thread_is_forked()) close (s->reader_pipe);
1398 
1399   return SANE_STATUS_GOOD;
1400 
1401 stop_scanner_and_return:
1402   do_cancel (s);
1403   return status;
1404 }
1405 
1406 
1407 SANE_Status
sane_read(SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len)1408 sane_read (SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len)
1409 {
1410   Tamarack_Scanner *s = handle;
1411   ssize_t nread;
1412 
1413   *len = 0;
1414 
1415   nread = read (s->pipe, buf, max_len);
1416   DBG(3, "read %ld bytes\n", (long) nread);
1417 
1418   if (!s->scanning)
1419     return do_cancel (s);
1420 
1421   if (nread < 0) {
1422     if (errno == EAGAIN) {
1423       return SANE_STATUS_GOOD;
1424     } else {
1425       do_cancel (s);
1426       return SANE_STATUS_IO_ERROR;
1427     }
1428   }
1429 
1430   *len = nread;
1431 
1432   if (nread == 0) {
1433     s->pass++;
1434     return do_eof (s);
1435   }
1436   return SANE_STATUS_GOOD;
1437 }
1438 
1439 
1440 void
sane_cancel(SANE_Handle handle)1441 sane_cancel (SANE_Handle handle)
1442 {
1443   Tamarack_Scanner *s = handle;
1444 
1445   if (sanei_thread_is_valid (s->reader_pid))
1446     sanei_thread_kill (s->reader_pid);
1447   s->scanning = SANE_FALSE;
1448 }
1449 
1450 
1451 SANE_Status
sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking)1452 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
1453 {
1454   Tamarack_Scanner *s = handle;
1455 
1456   if (!s->scanning)
1457     return SANE_STATUS_INVAL;
1458 
1459   if (fcntl (s->pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0)
1460     return SANE_STATUS_IO_ERROR;
1461 
1462   return SANE_STATUS_GOOD;
1463 }
1464 
1465 
1466 SANE_Status
sane_get_select_fd(SANE_Handle handle, SANE_Int *fd)1467 sane_get_select_fd (SANE_Handle handle, SANE_Int *fd)
1468 {
1469   Tamarack_Scanner *s = handle;
1470 
1471   if (!s->scanning)
1472     return SANE_STATUS_INVAL;
1473 
1474   *fd = s->pipe;
1475   return SANE_STATUS_GOOD;
1476 }
1477