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