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