1 /* sane - Scanner Access Now Easy.
2 Artec AS6E backend.
3 Copyright (C) 2000 Eugene S. Weiss
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 As a special exception, the authors of SANE give permission for
20 additional uses of the libraries contained in this release of SANE.
21
22 The exception is that, if you link a SANE library with other files
23 to produce an executable, this does not by itself cause the
24 resulting executable to be covered by the GNU General Public
25 License. Your use of that executable is in no way restricted on
26 account of linking the SANE library code into it.
27
28 This exception does not, however, invalidate any other reasons why
29 the executable file might be covered by the GNU General Public
30 License.
31
32 If you submit changes to SANE to the maintainers to be included in
33 a subsequent release, you agree by submitting the changes that
34 those changes may be distributed with this exception intact.
35
36 If you write modifications of your own for SANE, it is your choice
37 whether to permit this exception to apply to your modifications.
38 If you do not wish that, delete this exception notice.
39
40 This file implements a backend for the Artec AS6E by making a bridge
41 to the as6edriver program. The as6edriver program can be found at
42 http://as6edriver.sourceforge.net . */
43
44
45
46
47 #include "../include/sane/config.h"
48 #include <string.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <ctype.h>
53 #include <limits.h>
54 #include <stdarg.h>
55 #include <string.h>
56 #include <signal.h>
57 #include <sys/stat.h>
58
59 #include "../include/sane/sane.h"
60 #include "../include/sane/saneopts.h"
61
62 #define BACKENDNAME as6e
63 #include "../include/sane/sanei_backend.h"
64 #include "../include/sane/sanei_config.h"
65
66 #include "as6e.h"
67
68 static int num_devices;
69 static AS6E_Device *first_dev;
70 static AS6E_Scan *first_handle;
71 static const SANE_Device **devlist = 0;
72
73 static SANE_Status attach (const char *devname, AS6E_Device ** devp);
74 /* static SANE_Status attach_one (const char *dev); */
75
76 static const SANE_String_Const mode_list[] = {
77 SANE_VALUE_SCAN_MODE_LINEART,
78 SANE_VALUE_SCAN_MODE_GRAY,
79 SANE_VALUE_SCAN_MODE_COLOR,
80 0
81 };
82
83 static const SANE_Word resolution_list[] = {
84 4, 300, 200, 100, 50
85 };
86
87 static const SANE_Range x_range = {
88 SANE_FIX (0),
89 SANE_FIX (215.91),
90 SANE_FIX (0)
91 };
92
93 static const SANE_Range y_range = {
94 SANE_FIX (0),
95 SANE_FIX (297.19),
96 SANE_FIX (0)
97 };
98
99
100 static const SANE_Range brightness_range = {
101 -100,
102 100,
103 1
104 };
105
106 static const SANE_Range contrast_range = {
107 -100,
108 100,
109 1
110 };
111
112 /*--------------------------------------------------------------------------*/
113 static SANE_Int
as6e_unit_convert(SANE_Fixed value)114 as6e_unit_convert (SANE_Fixed value)
115 {
116
117 double precise;
118 SANE_Int return_value;
119
120 precise = SANE_UNFIX (value);
121 precise = (precise * 300) / MM_PER_INCH;
122 return_value = precise;
123 return return_value;
124 }
125
126 /*--------------------------------------------------------------------------*/
127
128 SANE_Status
sane_read(SANE_Handle handle,SANE_Byte * buf,SANE_Int max_len,SANE_Int * len)129 sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
130 SANE_Int * len)
131 {
132 AS6E_Scan *s = handle;
133 SANE_Word buffer_offset = 0;
134 int written = 0, bytes_read = 0, maxbytes;
135 SANE_Word bytecounter, linebufcounter, ctlbytes;
136 SANE_Byte *linebuffer;
137
138 DBG (3, "reading %d bytes, %d bytes in carryover buffer\n", max_len,
139 s->scan_buffer_count);
140
141 if ((unsigned int) s->image_counter >= s->bytes_to_read)
142 {
143 *len = 0;
144 if (s->scanning)
145 {
146 read (s->as6e_params.ctlinpipe, &written, sizeof (written));
147 if (written != -1)
148 DBG (3, "pipe error\n");
149 DBG (3, "trying to read -1 ...written = %d\n", written);
150 }
151 s->scanning = SANE_FALSE;
152 DBG (1, "image data complete, sending EOF...\n");
153 return SANE_STATUS_EOF;
154 } /*image complete */
155
156 linebuffer = s->line_buffer;
157 if (s->scan_buffer_count > 0)
158 { /*there are leftover bytes from the last call */
159 if (s->scan_buffer_count <= max_len)
160 {
161 for (*len = 0; *len < s->scan_buffer_count; (*len)++)
162 {
163 buf[*len] = s->scan_buffer[*len];
164 buffer_offset++;
165 }
166 s->scan_buffer_count = 0;
167 if (s->scan_buffer_count == max_len)
168 {
169 s->scan_buffer_count = 0;
170 s->image_counter += max_len;
171 DBG (3, "returning %d bytes from the carryover buffer\n", *len);
172 return SANE_STATUS_GOOD;
173 }
174 }
175 else
176 {
177 for (*len = 0; *len < max_len; (*len)++)
178 buf[*len] = s->scan_buffer[*len];
179
180 for (bytecounter = max_len;
181 bytecounter < s->scan_buffer_count; bytecounter++)
182 s->scan_buffer[bytecounter - max_len]
183 = s->scan_buffer[bytecounter];
184
185 s->scan_buffer_count -= max_len;
186 s->image_counter += max_len;
187 DBG (3, "returning %d bytes from the carryover buffer\n", *len);
188 return SANE_STATUS_GOOD;
189 }
190 }
191 else
192 {
193 *len = 0; /*no bytes in the buffer */
194 if (!s->scanning)
195 {
196 DBG (1, "scan over returning %d\n", *len);
197 if (s->scan_buffer_count)
198 return SANE_STATUS_GOOD;
199 else
200 return SANE_STATUS_EOF;
201 }
202 }
203 while (*len < max_len)
204 {
205 DBG (3, "trying to read number of bytes...\n");
206 ctlbytes = read (s->as6e_params.ctlinpipe, &written, sizeof (written));
207 DBG (3, "bytes written = %d, ctlbytes =%d\n", written, ctlbytes);
208 fflush (stdout);
209 if ((s->cancelled) && (written == 0))
210 { /*first clear -1 from pipe */
211 DBG (1, "sending SANE_STATUS_CANCELLED\n");
212 read (s->as6e_params.ctlinpipe, &written, sizeof (written));
213 s->scanning = SANE_FALSE;
214 return SANE_STATUS_CANCELLED;
215 }
216 if (written == -1)
217 {
218 DBG (1, "-1READ Scanner through. returning %d bytes\n", *len);
219 s->image_counter += *len;
220 s->scanning = SANE_FALSE;
221 return SANE_STATUS_GOOD;
222 }
223 linebufcounter = 0;
224 DBG (3,
225 "linebufctr reset, len =%d written =%d bytes_read =%d, max = %d\n",
226 *len, written, bytes_read, max_len);
227 maxbytes = written;
228 while (linebufcounter < written)
229 {
230 DBG (4, "trying to read data pipe\n");
231 bytes_read =
232 read (s->as6e_params.datapipe, linebuffer + linebufcounter,
233 maxbytes);
234 linebufcounter += bytes_read;
235 maxbytes -= bytes_read;
236 DBG (3, "bytes_read = %d linebufcounter = %d\n", bytes_read,
237 linebufcounter);
238 }
239 DBG (3, "written =%d max_len =%d len =%d\n", written, max_len, *len);
240 if (written <= (max_len - *len))
241 {
242 for (bytecounter = 0; bytecounter < written; bytecounter++)
243 {
244 buf[bytecounter + buffer_offset] = linebuffer[bytecounter];
245 (*len)++;
246 }
247 buffer_offset += written;
248 DBG (3, "buffer offset = %d\n", buffer_offset);
249 }
250 else if (max_len > *len)
251 { /*there's still room to send data */
252 for (bytecounter = 0; bytecounter < (max_len - *len); bytecounter++)
253 buf[bytecounter + buffer_offset] = linebuffer[bytecounter];
254 DBG (3, "topping off buffer\n");
255 for (bytecounter = (max_len - *len); bytecounter < written;
256 bytecounter++)
257 {
258
259 s->scan_buffer[s->scan_buffer_count + bytecounter -
260 (max_len - *len)] = linebuffer[bytecounter];
261 }
262 s->scan_buffer_count += (written - (max_len - *len));
263 *len = max_len;
264 }
265 else
266 { /*everything goes into the carryover buffer */
267 for (bytecounter = 0; bytecounter < written; bytecounter++)
268 s->scan_buffer[s->scan_buffer_count + bytecounter]
269 = linebuffer[bytecounter];
270 s->scan_buffer_count += written;
271 }
272 } /*while there's space in the buffer */
273 s->image_counter += *len;
274 DBG (3, "image ctr = %d bytes_to_read = %lu returning %d\n",
275 s->image_counter, (u_long) s->bytes_to_read, *len);
276
277 return SANE_STATUS_GOOD;
278 }
279
280 /*--------------------------------------------------------------------------*/
281 void
sane_cancel(SANE_Handle h)282 sane_cancel (SANE_Handle h)
283 {
284 AS6E_Scan *s = h;
285 SANE_Word test;
286 DBG (2, "trying to cancel...\n");
287 if (s->scanning)
288 {
289 test = kill (s->child_pid, SIGUSR1);
290 if (test == 0)
291 s->cancelled = SANE_TRUE;
292 }
293 }
294
295 /*--------------------------------------------------------------------------*/
296
297 SANE_Status
sane_start(SANE_Handle handle)298 sane_start (SANE_Handle handle)
299 {
300 AS6E_Scan *s = handle;
301 SANE_Status status;
302 int repeat = 1;
303 SANE_Word numbytes;
304 int scan_params[8];
305 /* First make sure we have a current parameter set. Some of the
306 * parameters will be overwritten below, but that's OK. */
307 DBG (2, "sane_start\n");
308 status = sane_get_parameters (s, 0);
309 if (status != SANE_STATUS_GOOD)
310 return status;
311 DBG (1, "Got params again...\n");
312 numbytes = write (s->as6e_params.ctloutpipe, &repeat, sizeof (repeat));
313 if (numbytes != sizeof (repeat))
314 return (SANE_STATUS_IO_ERROR);
315 DBG (1, "sending start_scan signal\n");
316 scan_params[0] = s->as6e_params.resolution;
317 if (strcmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0)
318 scan_params[1] = 0;
319 else if (strcmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY) == 0)
320 scan_params[1] = 1;
321 else if (strcmp (s->value[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART) == 0)
322 scan_params[1] = 2;
323 else
324 return (SANE_STATUS_JAMMED); /*this should never happen */
325 scan_params[2] = s->as6e_params.startpos;
326 scan_params[3] = s->as6e_params.stoppos;
327 scan_params[4] = s->as6e_params.startline;
328 scan_params[5] = s->as6e_params.stopline;
329 scan_params[6] = s->value[OPT_BRIGHTNESS].w;
330 scan_params[7] = s->value[OPT_CONTRAST].w;
331 DBG (1, "scan params = %d %d %d %d %d %d %d %d\n", scan_params[0],
332 scan_params[1], scan_params[2], scan_params[3],
333 scan_params[4], scan_params[5], scan_params[6], scan_params[7]);
334 numbytes =
335 write (s->as6e_params.ctloutpipe, scan_params, sizeof (scan_params));
336 if (numbytes != sizeof (scan_params))
337 return (SANE_STATUS_IO_ERROR);
338 s->scanning = SANE_TRUE;
339 s->scan_buffer_count = 0;
340 s->image_counter = 0;
341 s->cancelled = 0;
342 return (SANE_STATUS_GOOD);
343 }
344
345 /*--------------------------------------------------------------------------*/
346
347 SANE_Status
sane_get_parameters(SANE_Handle handle,SANE_Parameters * params)348 sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
349 {
350 AS6E_Scan *s = handle;
351 SANE_String mode;
352 SANE_Word divisor = 1;
353 DBG (2, "sane_get_parameters\n");
354 if (!s->scanning)
355 {
356 memset (&s->sane_params, 0, sizeof (s->sane_params));
357 s->as6e_params.resolution = s->value[OPT_RESOLUTION].w;
358 s->as6e_params.startpos = as6e_unit_convert (s->value[OPT_TL_X].w);
359 s->as6e_params.stoppos = as6e_unit_convert (s->value[OPT_BR_X].w);
360 s->as6e_params.startline = as6e_unit_convert (s->value[OPT_TL_Y].w);
361 s->as6e_params.stopline = as6e_unit_convert (s->value[OPT_BR_Y].w);
362 if ((s->as6e_params.resolution == 200)
363 || (s->as6e_params.resolution == 100))
364 divisor = 3;
365 else if (s->as6e_params.resolution == 50)
366 divisor = 6; /*get legal values for 200 dpi */
367 s->as6e_params.startpos = (s->as6e_params.startpos / divisor) * divisor;
368 s->as6e_params.stoppos = (s->as6e_params.stoppos / divisor) * divisor;
369 s->as6e_params.startline =
370 (s->as6e_params.startline / divisor) * divisor;
371 s->as6e_params.stopline = (s->as6e_params.stopline / divisor) * divisor;
372 s->sane_params.pixels_per_line =
373 (s->as6e_params.stoppos -
374 s->as6e_params.startpos) * s->as6e_params.resolution / 300;
375 s->sane_params.lines =
376 (s->as6e_params.stopline -
377 s->as6e_params.startline) * s->as6e_params.resolution / 300;
378 mode = s->value[OPT_MODE].s;
379 /* if ((strcmp (s->mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) ||
380 (strcmp (s->mode, SANE_VALUE_SCAN_MODE_HALFTONE) == 0))
381 {
382 s->sane_params.format = SANE_FRAME_GRAY;
383 s->sane_params.bytes_per_line = (s->sane_params.pixels_per_line + 7) / 8;
384 s->sane_params.depth = 1;
385 } */
386 /*else*/ if ((strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
387 || (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0))
388 {
389 s->sane_params.format = SANE_FRAME_GRAY;
390 s->sane_params.bytes_per_line = s->sane_params.pixels_per_line;
391 s->sane_params.depth = 8;
392 } /*grey frame */
393 else
394 {
395 s->sane_params.format = SANE_FRAME_RGB;
396 s->sane_params.bytes_per_line = 3 * s->sane_params.pixels_per_line;
397 s->sane_params.depth = 8;
398 } /*color frame */
399 s->bytes_to_read = s->sane_params.lines * s->sane_params.bytes_per_line;
400 s->sane_params.last_frame = SANE_TRUE;
401 } /*!scanning */
402
403 if (params)
404 *params = s->sane_params;
405 return (SANE_STATUS_GOOD);
406 }
407
408 /*--------------------------------------------------------------------------*/
409 SANE_Status
sane_control_option(SANE_Handle handle,SANE_Int option,SANE_Action action,void * val,SANE_Int * info)410 sane_control_option (SANE_Handle handle, SANE_Int option,
411 SANE_Action action, void *val, SANE_Int * info)
412 {
413 AS6E_Scan *s = handle;
414 SANE_Status status = 0;
415 SANE_Word cap;
416 DBG (2, "sane_control_option\n");
417 if (info)
418 *info = 0;
419 if (s->scanning)
420 return SANE_STATUS_DEVICE_BUSY;
421 if (option >= NUM_OPTIONS)
422 return SANE_STATUS_INVAL;
423 cap = s->options_list[option].cap;
424 if (!SANE_OPTION_IS_ACTIVE (cap))
425 return SANE_STATUS_INVAL;
426 if (action == SANE_ACTION_GET_VALUE)
427 {
428 DBG (1, "sane_control_option %d, get value\n", option);
429 switch (option)
430 {
431 /* word options: */
432 case OPT_RESOLUTION:
433 case OPT_TL_X:
434 case OPT_TL_Y:
435 case OPT_BR_X:
436 case OPT_BR_Y:
437 case OPT_NUM_OPTS:
438 case OPT_CONTRAST:
439 case OPT_BRIGHTNESS:
440 *(SANE_Word *) val = s->value[option].w;
441 return (SANE_STATUS_GOOD);
442 /* string options: */
443 case OPT_MODE:
444 strcpy (val, s->value[option].s);
445 return (SANE_STATUS_GOOD);
446 }
447 }
448 else if (action == SANE_ACTION_SET_VALUE)
449 {
450 DBG (1, "sane_control_option %d, set value\n", option);
451 if (!SANE_OPTION_IS_SETTABLE (cap))
452 return (SANE_STATUS_INVAL);
453 /* status = sanei_constrain_value (s->options_list[option], val, info);*/
454 if (status != SANE_STATUS_GOOD)
455 return (status);
456 switch (option)
457 {
458 /* (mostly) side-effect-free word options: */
459 case OPT_RESOLUTION:
460 case OPT_BR_X:
461 case OPT_BR_Y:
462 case OPT_TL_X:
463 case OPT_TL_Y:
464 if (info && s->value[option].w != *(SANE_Word *) val)
465 *info |= SANE_INFO_RELOAD_PARAMS;
466 /* fall through */
467 case OPT_NUM_OPTS:
468 case OPT_CONTRAST:
469 case OPT_BRIGHTNESS:
470 s->value[option].w = *(SANE_Word *) val;
471 DBG (1, "set brightness to\n");
472 return (SANE_STATUS_GOOD);
473 case OPT_MODE:
474 if (s->value[option].s)
475 free (s->value[option].s);
476 s->value[option].s = strdup (val);
477 return (SANE_STATUS_GOOD);
478 }
479 }
480 return (SANE_STATUS_INVAL);
481 }
482
483 /*--------------------------------------------------------------------------*/
484 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle,SANE_Int option)485 sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
486 {
487 AS6E_Scan *s = handle;
488 DBG (2, "sane_get_option_descriptor\n");
489 if ((unsigned) option >= NUM_OPTIONS)
490 return (0);
491 return (&s->options_list[option]);
492 }
493
494 /*--------------------------------------------------------------------------*/
495
496 void
sane_close(SANE_Handle handle)497 sane_close (SANE_Handle handle)
498 {
499 AS6E_Scan *prev, *s;
500 SANE_Word repeat = 0;
501 DBG (2, "sane_close\n");
502 /* remove handle from list of open handles: */
503 prev = 0;
504 for (s = first_handle; s; s = s->next)
505 {
506 if (s == handle)
507 break;
508 prev = s;
509 }
510 if (!s)
511 {
512 DBG (1, "close: invalid handle %p\n", handle);
513 return; /* oops, not a handle we know about */
514 }
515
516 if (s->scanning)
517 sane_cancel (handle);
518 write (s->as6e_params.ctloutpipe, &repeat, sizeof (repeat));
519 close (s->as6e_params.ctloutpipe);
520 free (s->scan_buffer);
521 free (s->line_buffer);
522 if (prev)
523 prev->next = s->next;
524 else
525 first_handle = s;
526 free (handle);
527 }
528
529 /*--------------------------------------------------------------------------*/
530 void
sane_exit(void)531 sane_exit (void)
532 {
533 AS6E_Device *next;
534 DBG (2, "sane_exit\n");
535 while (first_dev != NULL)
536 {
537 next = first_dev->next;
538 free (first_dev);
539 first_dev = next;
540 }
541 if (devlist)
542 free (devlist);
543 }
544
545 /*--------------------------------------------------------------------------*/
546 static SANE_Status
as6e_open(AS6E_Scan * s)547 as6e_open (AS6E_Scan * s)
548 {
549
550 int data_processed, exec_result, as6e_status;
551 int ctloutpipe[2], ctlinpipe[2], datapipe[2];
552 char inpipe_desc[32], outpipe_desc[32], datapipe_desc[32];
553 pid_t fork_result;
554 DBG (1, "as6e_open\n");
555 memset (inpipe_desc, '\0', sizeof (inpipe_desc));
556 memset (outpipe_desc, '\0', sizeof (outpipe_desc));
557 memset (datapipe_desc, '\0', sizeof (datapipe_desc));
558 if ((pipe (ctloutpipe) == 0) && (pipe (ctlinpipe) == 0)
559 && (pipe (datapipe) == 0))
560 {
561 fork_result = fork ();
562 if (fork_result == (pid_t) - 1)
563 {
564 DBG (1, "Fork failure");
565 return (SANE_STATUS_IO_ERROR);
566 }
567
568 if (fork_result == 0)
569 { /*in child */
570 sprintf (inpipe_desc, "%d", ctlinpipe[WRITEPIPE]);
571 sprintf (outpipe_desc, "%d", ctloutpipe[READPIPE]);
572 sprintf (datapipe_desc, "%d", datapipe[WRITEPIPE]);
573 exec_result =
574 execlp ("as6edriver", "as6edriver", "-s", inpipe_desc,
575 outpipe_desc, datapipe_desc, (char *) 0);
576 DBG (1, "The SANE backend was unable to start \"as6edriver\".\n");
577 DBG (1, "This must be installed in a directory in your PATH.\n");
578 DBG (1, "To acquire the as6edriver program,\n");
579 DBG (1, "go to http://as6edriver.sourceforge.net.\n");
580 write (ctlinpipe[WRITEPIPE], &exec_result, sizeof (exec_result));
581 exit (-1);
582 }
583 else
584 { /*parent process */
585 data_processed =
586 read (ctlinpipe[READPIPE], &as6e_status, sizeof (as6e_status));
587 DBG (1, "%d - read %d status = %d\n", getpid (), data_processed,
588 as6e_status);
589 if (as6e_status == -2)
590 {
591 DBG (1, "Port access denied.\n");
592 return (SANE_STATUS_IO_ERROR);
593 }
594 if (as6e_status == -1)
595 {
596 DBG (1, "Could not contact scanner.\n");
597 return (SANE_STATUS_IO_ERROR);
598 }
599
600 if (as6e_status == 1)
601 DBG (1, "Using nibble mode.\n");
602 if (as6e_status == 2)
603 DBG (1, "Using byte mode.\n");
604 if (as6e_status == 3)
605 DBG (1, "Using EPP mode.\n");
606 s->as6e_params.ctlinpipe = ctlinpipe[READPIPE];
607 s->as6e_params.ctloutpipe = ctloutpipe[WRITEPIPE];
608 s->as6e_params.datapipe = datapipe[READPIPE];
609 s->child_pid = fork_result;
610 return (SANE_STATUS_GOOD);
611 } /*else */
612 }
613 else
614 return (SANE_STATUS_IO_ERROR);
615 }
616
617
618 /*--------------------------------------------------------------------------*/
619 SANE_Status
sane_init(SANE_Int * version_code,SANE_Auth_Callback authorize)620 sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
621 {
622 char dev_name[PATH_MAX];
623 size_t len;
624 FILE *fp = NULL;
625
626 DBG_INIT ();
627 DBG (2, "sane_init (authorize %s null)\n", (authorize) ? "!=" : "==");
628 if (version_code)
629 *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, 0);
630 /* fp = sanei_config_open (AS6E_CONFIG_FILE);*/
631 if (!fp)
632 {
633 return (attach ("as6edriver", 0));
634 }
635
636 while (fgets (dev_name, sizeof (dev_name), fp))
637 {
638 if (dev_name[0] == '#') /* ignore line comments */
639 continue;
640 len = strlen (dev_name);
641 if (dev_name[len - 1] == '\n')
642 dev_name[--len] = '\0';
643 if (!len)
644 continue; /* ignore empty lines */
645 /* sanei_config_attach_matching_devices (dev_name, attach_one);*/
646 }
647 fclose (fp);
648 return (SANE_STATUS_GOOD);
649 }
650
651 /*--------------------------------------------------------------------------*/
652 /*
653 static SANE_Status
654 attach_one (const char *dev)
655 {
656 DBG (2, "attach_one\n");
657 attach (dev, 0);
658 return (SANE_STATUS_GOOD);
659 }
660 */
661 /*--------------------------------------------------------------------------*/
662 SANE_Status
sane_get_devices(const SANE_Device *** device_list,SANE_Bool local_only)663 sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
664 {
665 static const SANE_Device **devlist = 0;
666 AS6E_Device *dev;
667 int i;
668 DBG (3, "sane_get_devices (local_only = %d)\n", local_only);
669 if (devlist)
670 free (devlist);
671 devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
672 if (!devlist)
673 return SANE_STATUS_NO_MEM;
674 i = 0;
675 for (dev = first_dev; i < num_devices; dev = dev->next)
676 devlist[i++] = &dev->sane;
677 devlist[i++] = 0;
678 *device_list = devlist;
679 return (SANE_STATUS_GOOD);
680 }
681
682
683 /*--------------------------------------------------------------------------*/
684
685 static size_t
max_string_size(const SANE_String_Const strings[])686 max_string_size (const SANE_String_Const strings[])
687 {
688 size_t size, max_size = 0;
689 int i;
690 for (i = 0; strings[i]; ++i)
691 {
692 size = strlen (strings[i]) + 1;
693 if (size > max_size)
694 max_size = size;
695 }
696
697 return (max_size);
698 }
699
700 /*--------------------------------------------------------------------------*/
701
702 static void
initialize_options_list(AS6E_Scan * s)703 initialize_options_list (AS6E_Scan * s)
704 {
705
706 SANE_Int option;
707 DBG (2, "initialize_options_list\n");
708 for (option = 0; option < NUM_OPTIONS; ++option)
709 {
710 s->options_list[option].size = sizeof (SANE_Word);
711 s->options_list[option].cap =
712 SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
713 }
714
715 s->options_list[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
716 s->options_list[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
717 s->options_list[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
718 s->options_list[OPT_NUM_OPTS].type = SANE_TYPE_INT;
719 s->options_list[OPT_NUM_OPTS].unit = SANE_UNIT_NONE;
720 s->options_list[OPT_NUM_OPTS].size = sizeof (SANE_Word);
721 s->options_list[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
722 s->options_list[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE;
723 s->value[OPT_NUM_OPTS].w = NUM_OPTIONS;
724 s->options_list[OPT_MODE].name = SANE_NAME_SCAN_MODE;
725 s->options_list[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
726 s->options_list[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
727 s->options_list[OPT_MODE].type = SANE_TYPE_STRING;
728 s->options_list[OPT_MODE].size = max_string_size (mode_list);
729 s->options_list[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
730 s->options_list[OPT_MODE].constraint.string_list = mode_list;
731 s->value[OPT_MODE].s = strdup (mode_list[2]);
732 s->options_list[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
733 s->options_list[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
734 s->options_list[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
735 s->options_list[OPT_RESOLUTION].type = SANE_TYPE_INT;
736 s->options_list[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
737 s->options_list[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
738 s->options_list[OPT_RESOLUTION].constraint.word_list = resolution_list;
739 s->value[OPT_RESOLUTION].w = 200;
740 s->options_list[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
741 s->options_list[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
742 s->options_list[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
743 s->options_list[OPT_TL_X].type = SANE_TYPE_FIXED;
744 s->options_list[OPT_TL_X].unit = SANE_UNIT_MM;
745 s->options_list[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
746 s->options_list[OPT_TL_X].constraint.range = &x_range;
747 s->value[OPT_TL_X].w = s->options_list[OPT_TL_X].constraint.range->min;
748 s->options_list[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
749 s->options_list[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
750 s->options_list[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
751 s->options_list[OPT_TL_Y].type = SANE_TYPE_FIXED;
752 s->options_list[OPT_TL_Y].unit = SANE_UNIT_MM;
753 s->options_list[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
754 s->options_list[OPT_TL_Y].constraint.range = &y_range;
755 s->value[OPT_TL_Y].w = s->options_list[OPT_TL_Y].constraint.range->min;
756 s->options_list[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
757 s->options_list[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
758 s->options_list[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
759 s->options_list[OPT_BR_X].type = SANE_TYPE_FIXED;
760 s->options_list[OPT_BR_X].unit = SANE_UNIT_MM;
761 s->options_list[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
762 s->options_list[OPT_BR_X].constraint.range = &x_range;
763 s->value[OPT_BR_X].w = s->options_list[OPT_BR_X].constraint.range->max;
764 s->options_list[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
765 s->options_list[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
766 s->options_list[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
767 s->options_list[OPT_BR_Y].type = SANE_TYPE_FIXED;
768 s->options_list[OPT_BR_Y].unit = SANE_UNIT_MM;
769 s->options_list[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
770 s->options_list[OPT_BR_Y].constraint.range = &y_range;
771 s->value[OPT_BR_Y].w = s->options_list[OPT_BR_Y].constraint.range->max;
772 s->options_list[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
773 s->options_list[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
774 s->options_list[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
775 s->options_list[OPT_CONTRAST].type = SANE_TYPE_INT;
776 s->options_list[OPT_CONTRAST].unit = SANE_UNIT_NONE;
777 s->options_list[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
778 s->options_list[OPT_CONTRAST].constraint.range = &brightness_range;
779 s->value[OPT_BRIGHTNESS].w = 10;
780 s->options_list[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
781 s->options_list[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
782 s->options_list[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
783 s->options_list[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
784 s->options_list[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
785 s->options_list[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
786 s->options_list[OPT_BRIGHTNESS].constraint.range = &contrast_range;
787 s->value[OPT_CONTRAST].w = -32;
788 }
789
790 /*--------------------------------------------------------------------------*/
791 static int
check_for_driver(const char * devname)792 check_for_driver (const char *devname)
793 {
794 #define NAMESIZE 128
795 struct stat statbuf;
796 mode_t modes;
797 char *path;
798 char dir[NAMESIZE];
799 int count = 0, offset = 0, valid;
800
801 path = getenv ("PATH");
802 if (!path)
803 return 0;
804 while (path[count] != '\0')
805 {
806 memset (dir, '\0', sizeof (dir));
807 valid = 1;
808 while ((path[count] != ':') && (path[count] != '\0'))
809 {
810 /* prevent writing data, which are out of bounds */
811 if ((unsigned int)(count - offset) < sizeof (dir))
812 dir[count - offset] = path[count];
813 else
814 valid = 0;
815 count++;
816 }
817 if (valid == 1)
818 {
819 char fullname[NAMESIZE];
820 int len = snprintf(fullname, sizeof(fullname), "%s/%s", dir, devname);
821 if ((len > 0) && (len <= (int)sizeof(fullname)))
822 {
823 if (!stat (fullname, &statbuf))
824 {
825 modes = statbuf.st_mode;
826 if (S_ISREG (modes))
827 return (1); /* found as6edriver */
828 }
829 }
830 }
831 if (path[count] == '\0')
832 return (0); /* end of path --no driver found */
833 count++;
834 offset = count;
835 }
836 return (0);
837 }
838
839
840 /*--------------------------------------------------------------------------*/
841 static SANE_Status
attach(const char * devname,AS6E_Device ** devp)842 attach (const char *devname, AS6E_Device ** devp)
843 {
844
845 AS6E_Device *dev;
846
847 /* SANE_Status status; */
848 DBG (2, "attach\n");
849 for (dev = first_dev; dev; dev = dev->next)
850 {
851 if (strcmp (dev->sane.name, devname) == 0)
852 {
853 if (devp)
854 *devp = dev;
855 return (SANE_STATUS_GOOD);
856 }
857 }
858 dev = malloc (sizeof (*dev));
859 if (!dev)
860 return (SANE_STATUS_NO_MEM);
861 memset (dev, 0, sizeof (*dev));
862 dev->sane.name = strdup (devname);
863 if (!check_for_driver (devname))
864 {
865 free (dev);
866 return (SANE_STATUS_INVAL);
867 }
868
869 dev->sane.model = "AS6E";
870 dev->sane.vendor = "Artec";
871 dev->sane.type = "flatbed scanner";
872 ++num_devices;
873 dev->next = first_dev;
874 first_dev = dev;
875 if (devp)
876 *devp = dev;
877 return (SANE_STATUS_GOOD);
878 }
879
880
881 /*--------------------------------------------------------------------------*/
882 SANE_Status
sane_open(SANE_String_Const devicename,SANE_Handle * handle)883 sane_open (SANE_String_Const devicename, SANE_Handle * handle)
884 {
885 SANE_Status status;
886 AS6E_Device *dev;
887 AS6E_Scan *s;
888 DBG (2, "sane_open\n");
889 if (devicename[0])
890 {
891 for (dev = first_dev; dev; dev = dev->next)
892 if (strcmp (dev->sane.name, devicename) == 0)
893 break;
894 if (!dev)
895 {
896 status = attach (devicename, &dev);
897 if (status != SANE_STATUS_GOOD)
898 return (status);
899 }
900 }
901 else
902 {
903 /* empty devicname -> use first device */
904 dev = first_dev;
905 }
906 if (!dev)
907 return SANE_STATUS_INVAL;
908 s = malloc (sizeof (*s));
909 if (!s)
910 return SANE_STATUS_NO_MEM;
911 memset (s, 0, sizeof (*s));
912 s->scan_buffer = malloc (SCAN_BUF_SIZE);
913 if (!s->scan_buffer)
914 return SANE_STATUS_NO_MEM;
915 memset (s->scan_buffer, 0, SCAN_BUF_SIZE);
916 s->line_buffer = malloc (SCAN_BUF_SIZE);
917 if (!s->line_buffer)
918 return SANE_STATUS_NO_MEM;
919 memset (s->line_buffer, 0, SCAN_BUF_SIZE);
920 status = as6e_open (s);
921 if (status != SANE_STATUS_GOOD)
922 return status;
923 initialize_options_list (s);
924 s->scanning = 0;
925 /* insert newly opened handle into list of open handles: */
926 s->next = first_handle;
927 first_handle = s;
928 *handle = s;
929 return (status);
930 }
931
932 /*--------------------------------------------------------------------------*/
933 SANE_Status
sane_set_io_mode(SANE_Handle handle,SANE_Bool non_blocking)934 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
935 {
936 DBG (2, "sane_set_io_mode( %p, %d )\n", handle, non_blocking);
937 return (SANE_STATUS_UNSUPPORTED);
938 }
939
940 /*---------------------------------------------------------------------------*/
941 SANE_Status
sane_get_select_fd(SANE_Handle handle,SANE_Int * fd)942 sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
943 {
944 DBG (2, "sane_get_select_fd( %p, %p )\n",(void *) handle, (void *) fd);
945 return SANE_STATUS_UNSUPPORTED;
946 }
947