1 /* sane - Scanner Access Now Easy.
2 Copyright (C) 1997 Gordon Matzigkeit
3 Copyright (C) 1997 David Mosberger-Tang
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 #include "../include/sane/config.h"
41
42 #include <limits.h>
43 #include <stdlib.h>
44 #include <string.h>
45 extern int errno;
46
47 #include "../include/sane/sane.h"
48 #include "../include/sane/saneopts.h"
49
50 #include <unistd.h>
51 #include <fcntl.h>
52
53 #include "../include/sane/sanei_backend.h"
54
55 #ifndef PATH_MAX
56 # define PATH_MAX 1024
57 #endif
58
59 #include "../include/sane/sanei_config.h"
60 #define PINT_CONFIG_FILE "pint.conf"
61
62 #include "pint.h"
63
64 #define DECIPOINTS_PER_MM (720.0 / MM_PER_INCH)
65 #define TWELVEHUNDS_PER_MM (1200.0 / MM_PER_INCH)
66
67
68 static int num_devices;
69 static PINT_Device *first_dev;
70 static PINT_Scanner *first_handle;
71
72 /* A zero-terminated list of valid scanner modes. */
73 static SANE_String_Const mode_list[8];
74
75 static const SANE_Range s7_range =
76 {
77 -127, /* minimum */
78 127, /* maximum */
79 1 /* quantization */
80 };
81
82 static size_t
max_string_size(const SANE_String_Const strings[])83 max_string_size (const SANE_String_Const strings[])
84 {
85 size_t size, max_size = 0;
86 int i;
87
88 for (i = 0; strings[i]; ++i)
89 {
90 size = strlen (strings[i]) + 1;
91 if (size > max_size)
92 max_size = size;
93 }
94 return max_size;
95 }
96
97 static SANE_Status
attach(const char *devname, PINT_Device **devp)98 attach (const char *devname, PINT_Device **devp)
99 {
100 int fd;
101 long lastguess, inc;
102 PINT_Device *dev;
103 struct scan_io scanio;
104
105 for (dev = first_dev; dev; dev = dev->next)
106 if (strcmp (dev->sane.name, devname) == 0)
107 {
108 if (devp)
109 *devp = dev;
110 return SANE_STATUS_GOOD;
111 }
112
113 DBG(3, "attach: opening %s\n", devname);
114 fd = open (devname, O_RDONLY, 0);
115 if (fd < 0)
116 {
117 DBG(1, "attach: open failed (%s)\n", strerror (errno));
118 return SANE_STATUS_INVAL;
119 }
120
121 DBG(3, "attach: sending SCIOCGET\n");
122 if (ioctl (fd, SCIOCGET, &scanio) < 0)
123 {
124 DBG(1, "attach: get status failed (%s)\n", strerror (errno));
125 close (fd);
126 return SANE_STATUS_INVAL;
127 }
128
129 dev = malloc (sizeof (*dev));
130 if (!dev)
131 return SANE_STATUS_NO_MEM;
132
133 memset(dev, 0, sizeof (*dev));
134
135 /* Copy the original scanner state to the device structure. */
136 memcpy (&dev->scanio, &scanio, sizeof (dev->scanio));
137
138 /* FIXME: PINT currently has no good way to determine maxima and minima.
139 So, do binary searches to find out what limits the driver has. */
140
141 /* Assume that minimum range of x and y is 0. */
142 dev->x_range.min = SANE_FIX (0);
143 dev->y_range.min = SANE_FIX (0);
144 dev->x_range.quant = 0;
145 dev->y_range.quant = 0;
146
147 /* x range */
148 inc = 8.5 * 1200;
149
150 /* Converge on the maximum scan width. */
151 while ((inc /= 2) != 0)
152 {
153 /* Move towards the extremum until we overflow. */
154 do
155 {
156 lastguess = scanio.scan_width;
157 scanio.scan_width += inc;
158 }
159 while (ioctl (fd, SCIOCSET, &scanio) >= 0);
160
161 /* Pick the last valid guess, divide by two, and try again. */
162 scanio.scan_width = lastguess;
163 }
164 dev->x_range.max = SANE_FIX (scanio.scan_width / TWELVEHUNDS_PER_MM);
165
166 /* y range */
167 inc = 11 * 1200;
168 while ((inc /= 2) != 0)
169 {
170 do
171 {
172 lastguess = scanio.scan_height;
173 scanio.scan_height += inc;
174 }
175 while (ioctl (fd, SCIOCSET, &scanio) >= 0);
176 scanio.scan_height = lastguess;
177 }
178 dev->y_range.max = SANE_FIX (scanio.scan_height / TWELVEHUNDS_PER_MM);
179
180 /* Converge on the minimum scan resolution. */
181 dev->dpi_range.quant = 1;
182
183 if (scanio.scan_x_resolution > scanio.scan_y_resolution)
184 scanio.scan_x_resolution = scanio.scan_y_resolution;
185 else
186 scanio.scan_y_resolution = scanio.scan_x_resolution;
187
188 inc = -scanio.scan_x_resolution;
189 while ((inc /= 2) != 0)
190 {
191 do
192 {
193 lastguess = scanio.scan_x_resolution;
194 scanio.scan_x_resolution = scanio.scan_y_resolution += inc;
195 }
196 while (ioctl (fd, SCIOCSET, &scanio) >= 0);
197 scanio.scan_x_resolution = scanio.scan_y_resolution = lastguess;
198 }
199 dev->dpi_range.min = scanio.scan_x_resolution;
200
201 /* Converge on the maximum scan resolution. */
202 inc = 600;
203 while ((inc /= 2) != 0)
204 {
205 do
206 {
207 lastguess = scanio.scan_x_resolution;
208 scanio.scan_x_resolution = scanio.scan_y_resolution += inc;
209 }
210 while (ioctl (fd, SCIOCSET, &scanio) >= 0);
211 scanio.scan_x_resolution = scanio.scan_y_resolution = lastguess;
212 }
213 dev->dpi_range.max = scanio.scan_x_resolution;
214
215 /* Determine the valid scan modes for mode_list. */
216 lastguess = 0;
217 #define CHECK_MODE(flag,modename) \
218 scanio.scan_image_mode = flag; \
219 if (ioctl (fd, SCIOCSET, &scanio) >= 0) \
220 mode_list[lastguess ++] = modename
221
222 CHECK_MODE(SIM_BINARY_MONOCHROME, SANE_VALUE_SCAN_MODE_LINEART);
223 CHECK_MODE(SIM_DITHERED_MONOCHROME, SANE_VALUE_SCAN_MODE_HALFTONE);
224 CHECK_MODE(SIM_GRAYSCALE, SANE_VALUE_SCAN_MODE_GRAY);
225 CHECK_MODE(SIM_COLOR, SANE_VALUE_SCAN_MODE_COLOR);
226 CHECK_MODE(SIM_RED, "Red");
227 CHECK_MODE(SIM_GREEN, "Green");
228 CHECK_MODE(SIM_BLUE, "Blue");
229 #undef CHECK_MODE
230
231 /* Zero-terminate the list of modes. */
232 mode_list[lastguess] = 0;
233
234 /* Restore the scanner state. */
235 if (ioctl (fd, SCIOCSET, &dev->scanio))
236 DBG (2, "cannot reset original scanner state: %s\n", strerror (errno));
237 close (fd);
238
239 dev->sane.name = strdup (devname);
240
241 /* Determine vendor. */
242 switch (scanio.scan_scanner_type)
243 {
244 case EPSON_ES300C:
245 dev->sane.vendor = "Epson";
246 break;
247
248 case FUJITSU_M3096G:
249 dev->sane.vendor = "Fujitsu";
250 break;
251
252 case HP_SCANJET_IIC:
253 dev->sane.vendor = "HP";
254 break;
255
256 case IBM_2456:
257 dev->sane.vendor = "IBM";
258 break;
259
260 case MUSTEK_06000CX:
261 case MUSTEK_12000CX:
262 dev->sane.vendor = "Mustek";
263 break;
264
265 case RICOH_FS1:
266 case RICOH_IS410:
267 case RICOH_IS50:
268 dev->sane.vendor = "Ricoh";
269 break;
270
271 case SHARP_JX600:
272 dev->sane.vendor = "Sharp";
273 break;
274
275 case UMAX_UC630:
276 case UMAX_UG630:
277 dev->sane.vendor = "UMAX";
278 break;
279
280 default:
281 dev->sane.vendor = "PINT";
282 }
283
284 /* Determine model. */
285 switch (scanio.scan_scanner_type)
286 {
287 case EPSON_ES300C:
288 dev->sane.vendor = "Epson";
289 break;
290
291 case FUJITSU_M3096G:
292 dev->sane.model = "M3096G";
293 break;
294
295 case HP_SCANJET_IIC:
296 dev->sane.model = "ScanJet IIc";
297 break;
298
299 case IBM_2456:
300 dev->sane.vendor = "IBM";
301 break;
302
303 case MUSTEK_06000CX:
304 case MUSTEK_12000CX:
305 dev->sane.vendor = "Mustek";
306 break;
307
308 case RICOH_FS1:
309 dev->sane.model = "FS1";
310 break;
311
312 case RICOH_IS410:
313 dev->sane.model = "IS-410";
314 break;
315
316 case RICOH_IS50:
317 dev->sane.vendor = "Ricoh";
318 break;
319
320 case SHARP_JX600:
321 dev->sane.vendor = "Sharp";
322 break;
323
324 case UMAX_UC630:
325 case UMAX_UG630:
326 dev->sane.vendor = "UMAX";
327 break;
328
329 default:
330 dev->sane.model = "unknown";
331 }
332
333 /* Determine the scanner type. */
334 switch (scanio.scan_scanner_type)
335 {
336 case HP_SCANJET_IIC:
337 dev->sane.type = "flatbed scanner";
338
339 /* FIXME: which of these are flatbed or handhelds? */
340 case EPSON_ES300C:
341 case FUJITSU_M3096G:
342 case IBM_2456:
343 case MUSTEK_06000CX:
344 case MUSTEK_12000CX:
345 case RICOH_FS1:
346 case RICOH_IS410:
347 case RICOH_IS50:
348 case SHARP_JX600:
349 case UMAX_UC630:
350 case UMAX_UG630:
351 default:
352 dev->sane.type = "generic scanner";
353 }
354
355 DBG(1, "attach: found %s %s, x=%g-%gmm, y=%g-%gmm, "
356 "resolution=%d-%ddpi\n", dev->sane.vendor, dev->sane.model,
357 SANE_UNFIX (dev->x_range.min), SANE_UNFIX (dev->x_range.max),
358 SANE_UNFIX (dev->y_range.min), SANE_UNFIX (dev->y_range.max),
359 dev->dpi_range.min, dev->dpi_range.max);
360
361 ++num_devices;
362 dev->next = first_dev;
363 first_dev = dev;
364
365 if (devp)
366 *devp = dev;
367 return SANE_STATUS_GOOD;
368 }
369
370 static SANE_Status
init_options(PINT_Scanner *s)371 init_options (PINT_Scanner *s)
372 {
373 int i;
374 int x0, x1, y0, y1;
375
376 memset (s->opt, 0, sizeof (s->opt));
377 memset (s->val, 0, sizeof (s->val));
378
379 for (i = 0; i < NUM_OPTIONS; ++i)
380 {
381 s->opt[i].size = sizeof (SANE_Word);
382 s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
383 }
384
385 s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
386 s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
387 s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
388 s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
389 s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
390
391 /* "Mode" group: */
392 s->opt[OPT_MODE_GROUP].title = "Scan Mode";
393 s->opt[OPT_MODE_GROUP].desc = "";
394 s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
395 s->opt[OPT_MODE_GROUP].cap = 0;
396 s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
397
398 /* scan mode */
399 s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
400 s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
401 s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
402 s->opt[OPT_MODE].type = SANE_TYPE_STRING;
403 s->opt[OPT_MODE].size = max_string_size (mode_list);
404 s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
405 s->opt[OPT_MODE].constraint.string_list = mode_list;
406
407 /* Translate the current PINT mode into a string. */
408 switch (s->hw->scanio.scan_image_mode)
409 {
410 case SIM_BINARY_MONOCHROME:
411 s->val[OPT_MODE].s = strdup (mode_list[0]);
412 break;
413
414 case SIM_DITHERED_MONOCHROME:
415 s->val[OPT_MODE].s = strdup (mode_list[1]);
416 break;
417
418 case SIM_COLOR:
419 s->val[OPT_MODE].s = strdup (mode_list[3]);
420 break;
421
422 case SIM_RED:
423 s->val[OPT_MODE].s = strdup (mode_list[4]);
424 break;
425
426 case SIM_GREEN:
427 s->val[OPT_MODE].s = strdup (mode_list[5]);
428 break;
429
430 case SIM_BLUE:
431 s->val[OPT_MODE].s = strdup (mode_list[6]);
432 break;
433
434 case SIM_GRAYSCALE:
435 default:
436 s->val[OPT_MODE].s = strdup (mode_list[2]);
437 }
438
439 /* resolution */
440 s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
441 s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
442 s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
443 s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
444 s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
445 s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
446 s->opt[OPT_RESOLUTION].constraint.range = &s->hw->dpi_range;
447 s->val[OPT_RESOLUTION].w =
448 (s->hw->scanio.scan_x_resolution > s->hw->scanio.scan_y_resolution) ?
449 s->hw->scanio.scan_x_resolution : s->hw->scanio.scan_y_resolution;
450
451 /* "Geometry" group: */
452
453 s->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
454 s->opt[OPT_GEOMETRY_GROUP].desc = "";
455 s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
456 s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
457 s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
458
459 /* Calculate the x and y millimetre coordinates from the scanio. */
460 x0 = SANE_FIX (s->hw->scanio.scan_x_origin / TWELVEHUNDS_PER_MM);
461 y0 = SANE_FIX (s->hw->scanio.scan_y_origin / TWELVEHUNDS_PER_MM);
462 x1 = SANE_FIX ((s->hw->scanio.scan_x_origin + s->hw->scanio.scan_width)
463 / TWELVEHUNDS_PER_MM);
464 y1 = SANE_FIX ((s->hw->scanio.scan_y_origin + s->hw->scanio.scan_height)
465 / TWELVEHUNDS_PER_MM);
466
467 /* top-left x */
468 s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
469 s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
470 s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
471 s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
472 s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
473 s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
474 s->opt[OPT_TL_X].constraint.range = &s->hw->x_range;
475 s->val[OPT_TL_X].w = x0;
476
477 /* top-left y */
478 s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
479 s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
480 s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
481 s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
482 s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
483 s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
484 s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range;
485 s->val[OPT_TL_Y].w = y0;
486
487 /* bottom-right x */
488 s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
489 s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
490 s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
491 s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
492 s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
493 s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
494 s->opt[OPT_BR_X].constraint.range = &s->hw->x_range;
495 s->val[OPT_BR_X].w = x1;
496
497 /* bottom-right y */
498 s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
499 s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
500 s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
501 s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
502 s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
503 s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
504 s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range;
505 s->val[OPT_BR_Y].w = y1;
506
507 /* "Enhancement" group: */
508
509 s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
510 s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
511 s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
512 s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
513 s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
514
515 /* brightness */
516 s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
517 s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
518 s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
519 s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
520 s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
521 s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
522 s->opt[OPT_BRIGHTNESS].constraint.range = &s7_range;
523 s->val[OPT_BRIGHTNESS].w = s->hw->scanio.scan_brightness - 128;
524
525 /* contrast */
526 s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
527 s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
528 s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
529 s->opt[OPT_CONTRAST].type = SANE_TYPE_INT;
530 s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE;
531 s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
532 s->opt[OPT_CONTRAST].constraint.range = &s7_range;
533 s->val[OPT_CONTRAST].w = s->hw->scanio.scan_contrast - 128;
534 return SANE_STATUS_GOOD;
535 }
536
537 static SANE_Status
do_cancel(PINT_Scanner *s)538 do_cancel (PINT_Scanner *s)
539 {
540 /* FIXME: PINT doesn't have any good way to cancel ScanJets right now. */
541 #define gobble_up_buf_len 1024
542 char buf[gobble_up_buf_len];
543
544 /* Send the restart code. */
545 buf[0] = ioctl (s->fd, SCIOCRESTART, 0);
546
547 if (!s->scanning)
548 return SANE_STATUS_CANCELLED;
549
550 s->scanning = SANE_FALSE;
551
552 /* Read to the end of the file. */
553 while (read (s->fd, buf, gobble_up_buf_len) > 0)
554 ;
555 #undef gobble_up_buf_len
556
557 /* Finally, close the file descriptor. */
558 if (s->fd >= 0)
559 {
560 close (s->fd);
561 s->fd = -1;
562 }
563 return SANE_STATUS_CANCELLED;
564 }
565
566 SANE_Status
sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize)567 sane_init (SANE_Int *version_code, SANE_Auth_Callback authorize)
568 {
569 char dev_name[PATH_MAX];
570 size_t len;
571 FILE *fp;
572
573 DBG_INIT();
574
575 if (version_code)
576 *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
577
578 fp = sanei_config_open (PINT_CONFIG_FILE);
579 if (!fp)
580 {
581 /* default to /dev/scanner instead of insisting on config file */
582 attach ("/dev/scanner", 0);
583 return SANE_STATUS_GOOD;
584 }
585
586 while (sanei_config_read (dev_name, sizeof (dev_name), fp))
587 {
588 if (dev_name[0] == '#') /* ignore line comments */
589 continue;
590 len = strlen (dev_name);
591
592 if (!len)
593 continue; /* ignore empty lines */
594
595 attach (dev_name, 0);
596 }
597 fclose (fp);
598 return SANE_STATUS_GOOD;
599 }
600
601 void
sane_exit(void)602 sane_exit (void)
603 {
604 PINT_Device *dev, *next;
605
606 for (dev = first_dev; dev; dev = next)
607 {
608 next = dev->next;
609 free ((void *) dev->sane.name);
610 free (dev);
611 }
612 }
613
614 SANE_Status
sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)615 sane_get_devices (const SANE_Device ***device_list, SANE_Bool local_only)
616 {
617 static const SANE_Device **devlist = 0;
618 PINT_Device *dev;
619 int i;
620
621 if (devlist)
622 free (devlist);
623
624 devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
625 if (!devlist)
626 return SANE_STATUS_NO_MEM;
627
628 i = 0;
629 for (dev = first_dev; i < num_devices; dev = dev->next)
630 devlist[i++] = &dev->sane;
631 devlist[i++] = 0;
632
633 *device_list = devlist;
634 return SANE_STATUS_GOOD;
635 }
636
637 SANE_Status
sane_open(SANE_String_Const devicename, SANE_Handle *handle)638 sane_open (SANE_String_Const devicename, SANE_Handle *handle)
639 {
640 SANE_Status status;
641 PINT_Device *dev;
642 PINT_Scanner *s;
643
644 if (devicename[0])
645 {
646 for (dev = first_dev; dev; dev = dev->next)
647 if (strcmp (dev->sane.name, devicename) == 0)
648 break;
649
650 if (!dev)
651 {
652 status = attach (devicename, &dev);
653 if (status != SANE_STATUS_GOOD)
654 return status;
655 }
656 }
657 else
658 /* empty devicename -> use first device */
659 dev = first_dev;
660
661 if (!dev)
662 return SANE_STATUS_INVAL;
663
664 s = malloc (sizeof (*s));
665 if (!s)
666 return SANE_STATUS_NO_MEM;
667 memset (s, 0, sizeof (*s));
668 s->hw = dev;
669 s->fd = -1;
670
671 init_options (s);
672
673 /* insert newly opened handle into list of open handles: */
674 s->next = first_handle;
675 first_handle = s;
676
677 *handle = s;
678 return SANE_STATUS_GOOD;
679 }
680
681 void
sane_close(SANE_Handle handle)682 sane_close (SANE_Handle handle)
683 {
684 PINT_Scanner *prev, *s;
685
686 /* remove handle from list of open handles: */
687 prev = 0;
688 for (s = first_handle; s; s = s->next)
689 {
690 if (s == handle)
691 break;
692 prev = s;
693 }
694 if (!s)
695 {
696 DBG(1, "close: invalid handle %p\n", handle);
697 return; /* oops, not a handle we know about */
698 }
699
700 if (s->scanning)
701 do_cancel (handle);
702
703 if (prev)
704 prev->next = s->next;
705 else
706 first_handle = s->next;
707
708 free (handle);
709 }
710
711 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle, SANE_Int option)712 sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
713 {
714 PINT_Scanner *s = handle;
715
716 if ((unsigned) option >= NUM_OPTIONS)
717 return 0;
718 return s->opt + option;
719 }
720
721 SANE_Status
sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *val, SANE_Int *info)722 sane_control_option (SANE_Handle handle, SANE_Int option,
723 SANE_Action action, void *val, SANE_Int *info)
724 {
725 PINT_Scanner *s = handle;
726 SANE_Status status;
727 SANE_Word cap;
728
729 if (info)
730 *info = 0;
731
732 if (s->scanning)
733 return SANE_STATUS_DEVICE_BUSY;
734
735 if (option >= NUM_OPTIONS)
736 return SANE_STATUS_INVAL;
737
738 cap = s->opt[option].cap;
739
740 if (!SANE_OPTION_IS_ACTIVE (cap))
741 return SANE_STATUS_INVAL;
742
743 if (action == SANE_ACTION_GET_VALUE)
744 {
745 switch (option)
746 {
747 /* word options: */
748 case OPT_RESOLUTION:
749 case OPT_TL_X:
750 case OPT_TL_Y:
751 case OPT_BR_X:
752 case OPT_BR_Y:
753 case OPT_NUM_OPTS:
754 case OPT_BRIGHTNESS:
755 case OPT_CONTRAST:
756 *(SANE_Word *) val = s->val[option].w;
757 return SANE_STATUS_GOOD;
758
759 /* string options: */
760 case OPT_MODE:
761 strcpy (val, s->val[option].s);
762 return SANE_STATUS_GOOD;
763 }
764 }
765 else if (action == SANE_ACTION_SET_VALUE)
766 {
767 if (!SANE_OPTION_IS_SETTABLE (cap))
768 return SANE_STATUS_INVAL;
769
770 status = sanei_constrain_value (s->opt + option, val, info);
771 if (status != SANE_STATUS_GOOD)
772 return status;
773
774 switch (option)
775 {
776 /* (mostly) side-effect-free word options: */
777 case OPT_RESOLUTION:
778 case OPT_TL_X:
779 case OPT_TL_Y:
780 case OPT_BR_X:
781 case OPT_BR_Y:
782 if (info)
783 *info |= SANE_INFO_RELOAD_PARAMS;
784 /* fall through */
785 case OPT_NUM_OPTS:
786 case OPT_BRIGHTNESS:
787 case OPT_CONTRAST:
788 s->val[option].w = *(SANE_Word *) val;
789 return SANE_STATUS_GOOD;
790
791 case OPT_MODE:
792 if (s->val[option].s)
793 free (s->val[option].s);
794 s->val[option].s = strdup (val);
795 if (info)
796 *info |= SANE_INFO_RELOAD_PARAMS;
797 return SANE_STATUS_GOOD;
798 }
799 }
800 return SANE_STATUS_INVAL;
801 }
802
803 SANE_Status
sane_get_parameters(SANE_Handle handle, SANE_Parameters *params)804 sane_get_parameters (SANE_Handle handle, SANE_Parameters *params)
805 {
806 PINT_Scanner *s = handle;
807 struct scan_io scanio;
808
809 if (!s->scanning)
810 {
811 u_long x0, y0, width, height;
812 const char *mode;
813
814 /* Grab the scanio for this device. */
815 if (s->fd < 0)
816 {
817 s->fd = open (s->hw->sane.name, O_RDONLY, 0);
818 if (s->fd < 0)
819 {
820 DBG(1, "open of %s failed: %s\n",
821 s->hw->sane.name, strerror (errno));
822 return SANE_STATUS_INVAL;
823 }
824 }
825
826 if (ioctl (s->fd, SCIOCGET, &scanio) < 0)
827 {
828 DBG(1, "getting scanner state failed: %s", strerror (errno));
829 return SANE_STATUS_INVAL;
830 }
831
832 memset (&s->params, 0, sizeof (s->params));
833
834 /* FIXME: there is some lossage here: the parameters change due to
835 roundoff errors between converting to fixed point millimetres
836 and back. */
837 x0 = SANE_UNFIX (s->val[OPT_TL_X].w * TWELVEHUNDS_PER_MM);
838 y0 = SANE_UNFIX (s->val[OPT_TL_Y].w * TWELVEHUNDS_PER_MM);
839 width = SANE_UNFIX ((s->val[OPT_BR_X].w - s->val[OPT_TL_X].w)
840 * TWELVEHUNDS_PER_MM);
841 height = SANE_UNFIX ((s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w)
842 * TWELVEHUNDS_PER_MM);
843
844 /* x and y dpi: */
845 scanio.scan_x_resolution = s->val[OPT_RESOLUTION].w;
846 scanio.scan_y_resolution = s->val[OPT_RESOLUTION].w;
847
848 /* set scan extents, in 1/1200'ths of an inch */
849 scanio.scan_x_origin = x0;
850 scanio.scan_y_origin = y0;
851 scanio.scan_width = width;
852 scanio.scan_height = height;
853
854 /* brightness and contrast */
855 scanio.scan_brightness = s->val[OPT_BRIGHTNESS].w + 128;
856 scanio.scan_contrast = s->val[OPT_CONTRAST].w + 128;
857
858 /* set the scan image mode */
859 mode = s->val[OPT_MODE].s;
860 if (!strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART))
861 {
862 s->params.format = SANE_FRAME_GRAY;
863 scanio.scan_image_mode = SIM_BINARY_MONOCHROME;
864 }
865 else if (!strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE))
866 {
867 s->params.format = SANE_FRAME_GRAY;
868 scanio.scan_image_mode = SIM_DITHERED_MONOCHROME;
869 }
870 else if (!strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY))
871 {
872 s->params.format = SANE_FRAME_GRAY;
873 scanio.scan_image_mode = SIM_GRAYSCALE;
874 }
875 else if (!strcmp (mode, "Red"))
876 {
877 s->params.format = SANE_FRAME_RED;
878 scanio.scan_image_mode = SIM_RED;
879 }
880 else if (!strcmp (mode, "Green"))
881 {
882 s->params.format = SANE_FRAME_GREEN;
883 scanio.scan_image_mode = SIM_GREEN;
884 }
885 else if (!strcmp (mode, "Blue"))
886 {
887 s->params.format = SANE_FRAME_BLUE;
888 scanio.scan_image_mode = SIM_BLUE;
889 }
890 else
891 {
892 s->params.format = SANE_FRAME_RGB;
893 scanio.scan_image_mode = SIM_COLOR;
894 }
895
896 /* inquire resulting size of image after setting it up */
897 if (ioctl (s->fd, SCIOCSET, &scanio) < 0)
898 {
899 DBG(1, "setting scan parameters failed: %s", strerror (errno));
900 return SANE_STATUS_INVAL;
901 }
902 if (ioctl (s->fd, SCIOCGET, &scanio) < 0)
903 {
904 DBG(1, "getting scan parameters failed: %s", strerror (errno));
905 return SANE_STATUS_INVAL;
906 }
907
908 /* Save all the PINT-computed values. */
909 s->params.pixels_per_line = scanio.scan_pixels_per_line;
910 s->params.bytes_per_line =
911 (scanio.scan_bits_per_pixel * scanio.scan_pixels_per_line + 7) / 8;
912 s->params.lines = scanio.scan_lines;
913 s->params.depth = (scanio.scan_image_mode == SIM_COLOR) ?
914 scanio.scan_bits_per_pixel / 3 : scanio.scan_bits_per_pixel;
915
916 /* FIXME: this will need to be different for hand scanners. */
917 s->params.last_frame = SANE_TRUE;
918 }
919 if (params)
920 *params = s->params;
921 return SANE_STATUS_GOOD;
922 }
923
924 SANE_Status
sane_start(SANE_Handle handle)925 sane_start (SANE_Handle handle)
926 {
927 PINT_Scanner *s = handle;
928 SANE_Status status;
929
930 /* First make sure we have a current parameter set. This call actually
931 uses the PINT driver to do the calculations, so we trust its results. */
932 status = sane_get_parameters (s, 0);
933 if (status != SANE_STATUS_GOOD)
934 return status;
935
936 DBG(1, "%d pixels per line, %d bytes, %d lines high, dpi=%d\n",
937 s->params.pixels_per_line, s->params.bytes_per_line, s->params.lines,
938 s->val[OPT_RESOLUTION].w);
939
940 /* The scan is triggered in sane_read. */
941 s->scanning = SANE_TRUE;
942 return SANE_STATUS_GOOD;
943 }
944
945 SANE_Status
sane_read(SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len)946 sane_read (SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len)
947 {
948 PINT_Scanner *s = handle;
949 ssize_t nread;
950
951 *len = 0;
952
953 if (!s->scanning)
954 return do_cancel (s);
955
956 /* Verrry simple. Just suck up all the data PINT passes to us. */
957 nread = read (s->fd, buf, max_len);
958 if (nread <= 0)
959 {
960 do_cancel (s);
961 return (nread == 0) ? SANE_STATUS_EOF : SANE_STATUS_IO_ERROR;
962 }
963
964 *len = nread;
965 return SANE_STATUS_GOOD;
966 }
967
968 void
sane_cancel(SANE_Handle handle)969 sane_cancel (SANE_Handle handle)
970 {
971 PINT_Scanner *s = handle;
972 do_cancel (s);
973 }
974
975 SANE_Status
sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking)976 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
977 {
978 return SANE_STATUS_UNSUPPORTED;
979 }
980
981 SANE_Status
sane_get_select_fd(SANE_Handle handle, SANE_Int *fd)982 sane_get_select_fd (SANE_Handle handle, SANE_Int *fd)
983 {
984 return SANE_STATUS_UNSUPPORTED;
985 }
986