1 /* sane - Scanner Access Now Easy.
2
3 This file is part of the SANE package.
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18 As a special exception, the authors of SANE give permission for
19 additional uses of the libraries contained in this release of SANE.
20
21 The exception is that, if you link a SANE library with other files
22 to produce an executable, this does not by itself cause the
23 resulting executable to be covered by the GNU General Public
24 License. Your use of that executable is in no way restricted on
25 account of linking the SANE library code into it.
26
27 This exception does not, however, invalidate any other reasons why
28 the executable file might be covered by the GNU General Public
29 License.
30
31 If you submit changes to SANE to the maintainers to be included in
32 a subsequent release, you agree by submitting the changes that
33 those changes may be distributed with this exception intact.
34
35 If you write modifications of your own for SANE, it is your choice
36 whether to permit this exception to apply to your modifications.
37 If you do not wish that, delete this exception notice.
38 */
39
40 /*
41 This file implements a SANE backend for the Ibm 2456 flatbed scanner,
42 written by mf <massifr@tiscalinet.it>. It derives from the backend for
43 Ricoh flatbed scanners written by Feico W. Dillema.
44
45 Currently maintained by Henning Meier-Geinitz <henning@meier-geinitz.de>.
46 */
47
48 #define BUILD 5
49
50 #include "../include/sane/config.h"
51
52 #include <limits.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <string.h>
56 #include <sys/time.h>
57 #include <unistd.h>
58 #include <ctype.h>
59
60 #include "../include/sane/sane.h"
61 #include "../include/sane/saneopts.h"
62 #include "../include/sane/sanei_scsi.h"
63
64 #define BACKEND_NAME ibm
65 #include "../include/sane/sanei_backend.h"
66
67 #ifndef PATH_MAX
68 # define PATH_MAX 1024
69 #endif
70
71 #include "../include/sane/sanei_config.h"
72 #define IBM_CONFIG_FILE "ibm.conf"
73
74 #include "ibm.h"
75 #include "ibm-scsi.c"
76
77 #define MAX(a,b) ((a) > (b) ? (a) : (b))
78
79 static int num_devices = 0;
80 static Ibm_Device *first_dev = NULL;
81 static Ibm_Scanner *first_handle = NULL;
82 /* static int is50 = 0; */
83
84
85 static size_t
max_string_size(const SANE_String_Const strings[])86 max_string_size (const SANE_String_Const strings[])
87 {
88 size_t size, max_size = 0;
89 int i;
90 DBG (11, ">> max_string_size\n");
91
92 for (i = 0; strings[i]; ++i)
93 {
94 size = strlen (strings[i]) + 1;
95 if (size > max_size)
96 max_size = size;
97 }
98
99 DBG (11, "<< max_string_size\n");
100 return max_size;
101 }
102
103 static SANE_Status
attach(const char *devnam, Ibm_Device ** devp)104 attach (const char *devnam, Ibm_Device ** devp)
105 {
106 SANE_Status status;
107 Ibm_Device *dev;
108
109 int fd;
110 struct inquiry_data ibuf;
111 struct measurements_units_page mup;
112 struct ibm_window_data wbuf;
113 size_t buf_size;
114 char *str;
115 DBG (11, ">> attach\n");
116
117 for (dev = first_dev; dev; dev = dev->next)
118 {
119 if (strcmp (dev->sane.name, devnam) == 0)
120 {
121 if (devp)
122 *devp = dev;
123 return (SANE_STATUS_GOOD);
124 }
125 }
126
127 DBG (3, "attach: opening %s\n", devnam);
128 status = sanei_scsi_open (devnam, &fd, NULL, NULL);
129 if (status != SANE_STATUS_GOOD)
130 {
131 DBG (1, "attach: open failed: %s\n", sane_strstatus (status));
132 return (status);
133 }
134
135 DBG (3, "attach: sending INQUIRY\n");
136 memset (&ibuf, 0, sizeof (ibuf));
137 buf_size = sizeof(ibuf);
138 /* next line by mf */
139 ibuf.byte2 = 2;
140 status = inquiry (fd, &ibuf, &buf_size);
141 if (status != SANE_STATUS_GOOD)
142 {
143 DBG (1, "attach: inquiry failed: %s\n", sane_strstatus (status));
144 sanei_scsi_close (fd);
145 return (status);
146 }
147
148 if (ibuf.devtype != 6)
149 {
150 DBG (1, "attach: device \"%s\" is not a scanner\n", devnam);
151 sanei_scsi_close (fd);
152 return (SANE_STATUS_INVAL);
153 }
154
155 if (!(
156 (strncmp ((char *)ibuf.vendor, "IBM", 3) ==0
157 && strncmp ((char *)ibuf.product, "2456", 4) == 0)
158 || (strncmp ((char *)ibuf.vendor, "RICOH", 5) == 0
159 && strncmp ((char *)ibuf.product, "IS420", 5) == 0)
160 || (strncmp ((char *)ibuf.vendor, "RICOH", 5) == 0
161 && strncmp ((char *)ibuf.product, "IS410", 5) == 0)
162 || (strncmp ((char *)ibuf.vendor, "RICOH", 5) == 0
163 && strncmp ((char *)ibuf.product, "IS430", 5) == 0)
164 ))
165 {
166 DBG (1, "attach: device \"%s\" doesn't look like a scanner I know\n",
167 devnam);
168 sanei_scsi_close (fd);
169 return (SANE_STATUS_INVAL);
170 }
171
172 DBG (3, "attach: sending TEST_UNIT_READY\n");
173 status = test_unit_ready (fd);
174 if (status != SANE_STATUS_GOOD)
175 {
176 DBG (1, "attach: test unit ready failed (%s)\n",
177 sane_strstatus (status));
178 sanei_scsi_close (fd);
179 return (status);
180 }
181 /*
182 * Causes a problem with RICOH IS420
183 * Ignore this function ... seems to work ok
184 * Suggested to George Murphy george@topfloor.ie by henning
185 */
186 if (strncmp((char *)ibuf.vendor, "RICOH", 5) != 0
187 && strncmp((char *)ibuf.product, "IS420", 5) != 0)
188 {
189 DBG (3, "attach: sending OBJECT POSITION\n");
190 status = object_position (fd, OBJECT_POSITION_UNLOAD);
191 if (status != SANE_STATUS_GOOD)
192 {
193 DBG (1, "attach: OBJECT POSITION failed\n");
194 sanei_scsi_close (fd);
195 return (SANE_STATUS_INVAL);
196 }
197 }
198
199 memset (&mup, 0, sizeof (mup));
200 mup.page_code = MEASUREMENTS_PAGE;
201 mup.parameter_length = 0x06;
202 mup.bmu = INCHES;
203 mup.mud[0] = (DEFAULT_MUD >> 8) & 0xff;
204 mup.mud[1] = (DEFAULT_MUD & 0xff);
205
206 #if 0
207 DBG (3, "attach: sending MODE SELECT\n");
208 status = mode_select (fd, (struct mode_pages *) &mup);
209 if (status != SANE_STATUS_GOOD)
210 {
211 DBG (1, "attach: MODE_SELECT failed\n");
212 sanei_scsi_close (fd);
213 return (SANE_STATUS_INVAL);
214 }
215 #endif
216
217 #if 0
218 DBG (3, "attach: sending MODE SENSE\n");
219 memset (&mup, 0, sizeof (mup));
220 status = mode_sense (fd, (struct mode_pages *) &mup, PC_CURRENT | MEASUREMENTS_PAGE);
221 if (status != SANE_STATUS_GOOD)
222 {
223 DBG (1, "attach: MODE_SENSE failed\n");
224 sanei_scsi_close (fd);
225 return (SANE_STATUS_INVAL);
226 }
227 #endif
228
229 DBG (3, "attach: sending GET WINDOW\n");
230 memset (&wbuf, 0, sizeof (wbuf));
231 status = get_window (fd, &wbuf);
232 if (status != SANE_STATUS_GOOD)
233 {
234 DBG (1, "attach: GET_WINDOW failed %d\n", status);
235 sanei_scsi_close (fd);
236 DBG (11, "<< attach\n");
237 return (SANE_STATUS_INVAL);
238 }
239
240 sanei_scsi_close (fd);
241
242 dev = malloc (sizeof (*dev));
243 if (!dev)
244 return (SANE_STATUS_NO_MEM);
245 memset (dev, 0, sizeof (*dev));
246
247 dev->sane.name = strdup (devnam);
248 dev->sane.vendor = "IBM";
249
250 size_t prod_rev_size = sizeof(ibuf.product) + sizeof(ibuf.revision) + 1;
251 str = malloc (prod_rev_size);
252 if (str)
253 {
254 snprintf (str, prod_rev_size, "%.*s%.*s",
255 (int) sizeof(ibuf.product), (const char *) ibuf.product,
256 (int) sizeof(ibuf.revision), (const char *) ibuf.revision);
257 }
258 dev->sane.model = str;
259 dev->sane.type = "flatbed scanner";
260
261 DBG (5, "dev->sane.name = %s\n", dev->sane.name);
262 DBG (5, "dev->sane.vendor = %s\n", dev->sane.vendor);
263 DBG (5, "dev->sane.model = %s\n", dev->sane.model);
264 DBG (5, "dev->sane.type = %s\n", dev->sane.type);
265
266 dev->info.xres_default = _2btol(wbuf.x_res);
267 dev->info.yres_default = _2btol(wbuf.y_res);
268 dev->info.image_mode_default = wbuf.image_comp;
269
270 /* if you throw the MRIF bit the brightness control reverses too */
271 /* so I reverse the reversal in software for symmetry's sake */
272 /* I should make this into an option */
273
274 if (wbuf.image_comp == IBM_GRAYSCALE || wbuf.image_comp == IBM_DITHERED_MONOCHROME)
275 {
276 dev->info.brightness_default = 256 - wbuf.brightness;
277 /*
278 if (is50)
279 dev->info.contrast_default = wbuf.contrast;
280 else
281 */
282 dev->info.contrast_default = 256 - wbuf.contrast;
283 }
284 else /* wbuf.image_comp == IBM_BINARY_MONOCHROME */
285 {
286 dev->info.brightness_default = wbuf.brightness;
287 dev->info.contrast_default = wbuf.contrast;
288 }
289
290 /* da rivedere
291 dev->info.adf_default = wbuf.adf_state;
292 */
293 dev->info.adf_default = ADF_UNUSED;
294 dev->info.adf_default = IBM_PAPER_USER_DEFINED;
295
296 #if 1
297 dev->info.bmu = mup.bmu;
298 dev->info.mud = _2btol(mup.mud);
299 if (dev->info.mud == 0) {
300 /* The Ricoh says it uses points as default Basic Measurement Unit */
301 /* but gives a Measurement Unit Divisor of zero */
302 /* So, we set it to the default (SCSI-standard) of 1200 */
303 /* with BMU in inches, i.e. 1200 points equal 1 inch */
304 dev->info.bmu = INCHES;
305 dev->info.mud = DEFAULT_MUD;
306 }
307 #else
308 dev->info.bmu = INCHES;
309 dev->info.mud = DEFAULT_MUD;
310 #endif
311
312 DBG (5, "xres_default=%d\n", dev->info.xres_default);
313 DBG (5, "xres_range.max=%d\n", dev->info.xres_range.max);
314 DBG (5, "xres_range.min=%d\n", dev->info.xres_range.min);
315
316 DBG (5, "yres_default=%d\n", dev->info.yres_default);
317 DBG (5, "yres_range.max=%d\n", dev->info.yres_range.max);
318 DBG (5, "yres_range.min=%d\n", dev->info.yres_range.min);
319
320 DBG (5, "x_range.max=%d\n", dev->info.x_range.max);
321 DBG (5, "y_range.max=%d\n", dev->info.y_range.max);
322
323 DBG (5, "image_mode=%d\n", dev->info.image_mode_default);
324
325 DBG (5, "brightness=%d\n", dev->info.brightness_default);
326 DBG (5, "contrast=%d\n", dev->info.contrast_default);
327
328 DBG (5, "adf_state=%d\n", dev->info.adf_default);
329
330 DBG (5, "bmu=%d\n", dev->info.bmu);
331 DBG (5, "mud=%d\n", dev->info.mud);
332
333 ++num_devices;
334 dev->next = first_dev;
335 first_dev = dev;
336
337 if (devp)
338 *devp = dev;
339
340 DBG (11, "<< attach\n");
341 return (SANE_STATUS_GOOD);
342 }
343
344 static SANE_Status
attach_one(const char *devnam)345 attach_one(const char *devnam)
346 {
347 attach (devnam, NULL);
348 return SANE_STATUS_GOOD;
349 }
350
351 static SANE_Status
init_options(Ibm_Scanner * s)352 init_options (Ibm_Scanner * s)
353 {
354 int i;
355 DBG (11, ">> init_options\n");
356
357 memset (s->opt, 0, sizeof (s->opt));
358 memset (s->val, 0, sizeof (s->val));
359
360 for (i = 0; i < NUM_OPTIONS; ++i)
361 {
362 s->opt[i].size = sizeof (SANE_Word);
363 s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
364 }
365
366 s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
367 s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
368 s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
369 s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
370 s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
371
372 /* "Mode" group: */
373 s->opt[OPT_MODE_GROUP].title = "Scan Mode";
374 s->opt[OPT_MODE_GROUP].desc = "";
375 s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
376 s->opt[OPT_MODE_GROUP].cap = 0;
377 s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
378
379 /* scan mode */
380 s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
381 s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
382 s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
383 s->opt[OPT_MODE].type = SANE_TYPE_STRING;
384 s->opt[OPT_MODE].size = max_string_size (mode_list);
385 s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
386 s->opt[OPT_MODE].constraint.string_list = mode_list;
387 s->val[OPT_MODE].s = strdup (mode_list[s->hw->info.image_mode_default]);
388
389 /* x resolution */
390 s->opt[OPT_X_RESOLUTION].name = "X" SANE_NAME_SCAN_RESOLUTION;
391 s->opt[OPT_X_RESOLUTION].title = "X " SANE_TITLE_SCAN_RESOLUTION;
392 s->opt[OPT_X_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
393 s->opt[OPT_X_RESOLUTION].type = SANE_TYPE_INT;
394 s->opt[OPT_X_RESOLUTION].unit = SANE_UNIT_DPI;
395 s->opt[OPT_X_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
396 s->opt[OPT_X_RESOLUTION].constraint.range = &ibm2456_res_range;
397 s->val[OPT_X_RESOLUTION].w = s->hw->info.xres_default;
398 /*
399 if (is50)
400 s->opt[OPT_X_RESOLUTION].constraint.range = &is50_res_range;
401 else
402 */
403 s->opt[OPT_X_RESOLUTION].constraint.range = &ibm2456_res_range;
404
405 /* y resolution */
406 s->opt[OPT_Y_RESOLUTION].name = "Y" SANE_NAME_SCAN_RESOLUTION;
407 s->opt[OPT_Y_RESOLUTION].title = "Y " SANE_TITLE_SCAN_RESOLUTION;
408 s->opt[OPT_Y_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
409 s->opt[OPT_Y_RESOLUTION].type = SANE_TYPE_INT;
410 s->opt[OPT_Y_RESOLUTION].unit = SANE_UNIT_DPI;
411 s->opt[OPT_Y_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
412 s->val[OPT_Y_RESOLUTION].w = s->hw->info.yres_default;
413 s->opt[OPT_Y_RESOLUTION].constraint.range = &ibm2456_res_range;
414
415 /* adf */
416 s->opt[OPT_ADF].name = "adf";
417 s->opt[OPT_ADF].title = "Use ADF";
418 s->opt[OPT_ADF].desc = "Uses the automatic document feeder.";
419 s->opt[OPT_ADF].type = SANE_TYPE_BOOL;
420 s->opt[OPT_ADF].unit = SANE_UNIT_NONE;
421 s->opt[OPT_ADF].constraint_type = SANE_CONSTRAINT_NONE;
422 s->val[OPT_ADF].b = s->hw->info.adf_default;
423
424 /* "Geometry" group: */
425 s->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
426 s->opt[OPT_GEOMETRY_GROUP].desc = "";
427 s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
428 s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
429 s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
430
431 /* paper */
432 s->opt[OPT_PAPER].name = "paper";
433 s->opt[OPT_PAPER].title = "Paper format";
434 s->opt[OPT_PAPER].desc = "Sets the paper format.";
435 s->opt[OPT_PAPER].type = SANE_TYPE_STRING;
436 s->opt[OPT_PAPER].size = max_string_size (paper_list);
437 s->opt[OPT_PAPER].constraint_type = SANE_CONSTRAINT_STRING_LIST;
438 s->opt[OPT_PAPER].constraint.string_list = paper_list;
439 s->val[OPT_PAPER].s = strdup (paper_list[s->hw->info.paper_default]);
440
441 /* top-left x */
442 s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
443 s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
444 s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
445 s->opt[OPT_TL_X].type = SANE_TYPE_INT;
446 s->opt[OPT_TL_X].unit = SANE_UNIT_PIXEL;
447 s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
448 s->opt[OPT_TL_X].constraint.range = &default_x_range;
449 s->val[OPT_TL_X].w = 0;
450
451 /* top-left y */
452 s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
453 s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
454 s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
455 s->opt[OPT_TL_Y].type = SANE_TYPE_INT;
456 s->opt[OPT_TL_Y].unit = SANE_UNIT_PIXEL;
457 s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
458 s->opt[OPT_TL_Y].constraint.range = &default_y_range;
459 s->val[OPT_TL_Y].w = 0;
460
461 /* bottom-right x */
462 s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
463 s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
464 s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
465 s->opt[OPT_BR_X].type = SANE_TYPE_INT;
466 s->opt[OPT_BR_X].unit = SANE_UNIT_PIXEL;
467 s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
468 s->opt[OPT_BR_X].constraint.range = &default_x_range;
469 s->val[OPT_BR_X].w = default_x_range.max;
470
471 /* bottom-right y */
472 s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
473 s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
474 s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
475 s->opt[OPT_BR_Y].type = SANE_TYPE_INT;
476 s->opt[OPT_BR_Y].unit = SANE_UNIT_PIXEL;
477 s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
478 s->opt[OPT_BR_Y].constraint.range = &default_y_range;
479 s->val[OPT_BR_Y].w = default_y_range.max;
480
481 /* "Enhancement" group: */
482 s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
483 s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
484 s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
485 s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
486 s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
487
488 /* brightness */
489 s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
490 s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
491 s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
492 s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
493 s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
494 s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
495 s->opt[OPT_BRIGHTNESS].constraint.range = &u8_range;
496 s->val[OPT_BRIGHTNESS].w = s->hw->info.brightness_default;
497
498 /* contrast */
499 s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
500 s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
501 s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
502 s->opt[OPT_CONTRAST].type = SANE_TYPE_INT;
503 s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE;
504 s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
505 s->opt[OPT_CONTRAST].constraint.range = &u8_range;
506 s->val[OPT_CONTRAST].w = s->hw->info.contrast_default;
507
508 DBG (11, "<< init_options\n");
509 return SANE_STATUS_GOOD;
510 }
511
512 static SANE_Status
do_cancel(Ibm_Scanner * s)513 do_cancel (Ibm_Scanner * s)
514 {
515 SANE_Status status;
516 DBG (11, ">> do_cancel\n");
517
518 DBG (3, "cancel: sending OBJECT POSITION\n");
519 status = object_position (s->fd, OBJECT_POSITION_UNLOAD);
520 if (status != SANE_STATUS_GOOD)
521 {
522 DBG (1, "cancel: OBJECT POSITION failed\n");
523 }
524
525 s->scanning = SANE_FALSE;
526
527 if (s->fd >= 0)
528 {
529 sanei_scsi_close (s->fd);
530 s->fd = -1;
531 }
532
533 DBG (11, "<< do_cancel\n");
534 return (SANE_STATUS_CANCELLED);
535 }
536
537 SANE_Status
sane_init(SANE_Int * version_code, SANE_Auth_Callback authorize)538 sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
539 {
540 char devnam[PATH_MAX] = "/dev/scanner";
541 FILE *fp;
542
543 DBG_INIT ();
544 DBG (11, ">> sane_init (authorize %s null)\n", (authorize) ? "!=" : "==");
545
546 #if defined PACKAGE && defined VERSION
547 DBG (2, "sane_init: ibm backend version %d.%d-%d ("
548 PACKAGE " " VERSION ")\n", SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
549 #endif
550
551 if (version_code)
552 *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
553
554 fp = sanei_config_open(IBM_CONFIG_FILE);
555 if (fp)
556 {
557 char line[PATH_MAX], *lp;
558 size_t len;
559
560 /* read config file */
561 while (sanei_config_read (line, sizeof (line), fp))
562 {
563 if (line[0] == '#') /* ignore line comments */
564 continue;
565 len = strlen (line);
566
567 if (!len)
568 continue; /* ignore empty lines */
569
570 /* skip white space: */
571 for (lp = line; isspace(*lp); ++lp)
572 ;
573 strcpy (devnam, lp);
574 }
575 fclose (fp);
576 }
577 sanei_config_attach_matching_devices (devnam, attach_one);
578 DBG (11, "<< sane_init\n");
579 return SANE_STATUS_GOOD;
580 }
581
582 void
sane_exit(void)583 sane_exit (void)
584 {
585 Ibm_Device *dev, *next;
586 DBG (11, ">> sane_exit\n");
587
588 for (dev = first_dev; dev; dev = next)
589 {
590 next = dev->next;
591 free ((void *) dev->sane.name);
592 free ((void *) dev->sane.model);
593 free (dev);
594 }
595
596 DBG (11, "<< sane_exit\n");
597 }
598
599 SANE_Status
sane_get_devices(const SANE_Device *** device_list, SANE_Bool local_only)600 sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
601 {
602 static const SANE_Device **devlist = 0;
603 Ibm_Device *dev;
604 int i;
605 DBG (11, ">> sane_get_devices (local_only = %d)\n", local_only);
606
607 if (devlist)
608 free (devlist);
609 devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
610 if (!devlist)
611 return (SANE_STATUS_NO_MEM);
612
613 i = 0;
614 for (dev = first_dev; dev; dev = dev->next)
615 devlist[i++] = &dev->sane;
616 devlist[i++] = 0;
617
618 *device_list = devlist;
619
620 DBG (11, "<< sane_get_devices\n");
621 return SANE_STATUS_GOOD;
622 }
623
624 SANE_Status
sane_open(SANE_String_Const devnam, SANE_Handle * handle)625 sane_open (SANE_String_Const devnam, SANE_Handle * handle)
626 {
627 SANE_Status status;
628 Ibm_Device *dev;
629 Ibm_Scanner *s;
630 DBG (11, ">> sane_open\n");
631
632 if (devnam[0] == '\0')
633 {
634 for (dev = first_dev; dev; dev = dev->next)
635 {
636 if (strcmp (dev->sane.name, devnam) == 0)
637 break;
638 }
639
640 if (!dev)
641 {
642 status = attach (devnam, &dev);
643 if (status != SANE_STATUS_GOOD)
644 return (status);
645 }
646 }
647 else
648 {
649 dev = first_dev;
650 }
651
652 if (!dev)
653 return (SANE_STATUS_INVAL);
654
655 s = malloc (sizeof (*s));
656 if (!s)
657 return SANE_STATUS_NO_MEM;
658 memset (s, 0, sizeof (*s));
659
660 s->fd = -1;
661 s->hw = dev;
662
663 init_options (s);
664
665 s->next = first_handle;
666 first_handle = s;
667
668 *handle = s;
669
670 DBG (11, "<< sane_open\n");
671 return SANE_STATUS_GOOD;
672 }
673
674 void
sane_close(SANE_Handle handle)675 sane_close (SANE_Handle handle)
676 {
677 Ibm_Scanner *s = (Ibm_Scanner *) handle;
678 DBG (11, ">> sane_close\n");
679
680 if (s->fd != -1)
681 sanei_scsi_close (s->fd);
682 free (s);
683
684 DBG (11, ">> sane_close\n");
685 }
686
687 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle, SANE_Int option)688 sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
689 {
690 Ibm_Scanner *s = handle;
691 DBG (11, ">> sane_get_option_descriptor\n");
692
693 if ((unsigned) option >= NUM_OPTIONS)
694 return (0);
695
696 DBG (11, "<< sane_get_option_descriptor\n");
697 return (s->opt + option);
698 }
699
700 SANE_Status
sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *val, SANE_Int * info)701 sane_control_option (SANE_Handle handle, SANE_Int option,
702 SANE_Action action, void *val, SANE_Int * info)
703 {
704 Ibm_Scanner *s = handle;
705 SANE_Status status;
706 SANE_Word cap;
707 DBG (11, ">> sane_control_option\n");
708
709 if (info)
710 *info = 0;
711
712 if (s->scanning)
713 return (SANE_STATUS_DEVICE_BUSY);
714 if (option >= NUM_OPTIONS)
715 return (SANE_STATUS_INVAL);
716
717 cap = s->opt[option].cap;
718 if (!SANE_OPTION_IS_ACTIVE (cap))
719 return (SANE_STATUS_INVAL);
720
721 if (action == SANE_ACTION_GET_VALUE)
722 {
723 DBG (11, "sane_control_option get_value\n");
724 switch (option)
725 {
726 /* word options: */
727 case OPT_X_RESOLUTION:
728 case OPT_Y_RESOLUTION:
729 case OPT_TL_X:
730 case OPT_TL_Y:
731 case OPT_BR_X:
732 case OPT_BR_Y:
733 case OPT_NUM_OPTS:
734 case OPT_BRIGHTNESS:
735 case OPT_CONTRAST:
736 *(SANE_Word *) val = s->val[option].w;
737 return (SANE_STATUS_GOOD);
738
739 /* bool options: */
740 case OPT_ADF:
741 *(SANE_Bool *) val = s->val[option].b;
742 return (SANE_STATUS_GOOD);
743
744 /* string options: */
745 case OPT_MODE:
746 case OPT_PAPER:
747 strcpy (val, s->val[option].s);
748 return (SANE_STATUS_GOOD);
749 }
750 }
751 else {
752 DBG (11, "sane_control_option set_value\n");
753 if (action == SANE_ACTION_SET_VALUE)
754 {
755 if (!SANE_OPTION_IS_SETTABLE (cap))
756 return (SANE_STATUS_INVAL);
757
758 status = sanei_constrain_value (s->opt + option, val, info);
759 if (status != SANE_STATUS_GOOD)
760 return status;
761
762 switch (option)
763 {
764 /* (mostly) side-effect-free word options: */
765 case OPT_X_RESOLUTION:
766 case OPT_Y_RESOLUTION:
767 if (info && s->val[option].w != *(SANE_Word *) val)
768 *info |= SANE_INFO_RELOAD_PARAMS;
769 s->val[option].w = *(SANE_Word *) val;
770 return (SANE_STATUS_GOOD);
771
772 case OPT_TL_X:
773 case OPT_TL_Y:
774 case OPT_BR_X:
775 case OPT_BR_Y:
776 if (info && s->val[option].w != *(SANE_Word *) val)
777 *info |= SANE_INFO_RELOAD_PARAMS;
778 s->val[option].w = *(SANE_Word *) val;
779 /* resets the paper format to user defined */
780 if (strcmp(s->val[OPT_PAPER].s, paper_list[IBM_PAPER_USER_DEFINED]) != 0)
781 {
782 if (info)
783 *info |= SANE_INFO_RELOAD_OPTIONS;
784 if (s->val[OPT_PAPER].s)
785 free (s->val[OPT_PAPER].s);
786 s->val[OPT_PAPER].s = strdup (paper_list[IBM_PAPER_USER_DEFINED]);
787 }
788 return (SANE_STATUS_GOOD);
789
790 case OPT_NUM_OPTS:
791 case OPT_BRIGHTNESS:
792 case OPT_CONTRAST:
793 s->val[option].w = *(SANE_Word *) val;
794 return (SANE_STATUS_GOOD);
795
796 case OPT_MODE:
797 if (info && strcmp (s->val[option].s, (SANE_String) val))
798 *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
799 if (s->val[option].s)
800 free (s->val[option].s);
801 s->val[option].s = strdup (val);
802 return (SANE_STATUS_GOOD);
803
804 case OPT_ADF:
805 s->val[option].b = *(SANE_Bool *) val;
806 if (*(SANE_Bool *) val)
807 s->adf_state = ADF_ARMED;
808 else
809 s->adf_state = ADF_UNUSED;
810 return (SANE_STATUS_GOOD);
811
812 case OPT_PAPER:
813 if (info && strcmp (s->val[option].s, (SANE_String) val))
814 *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
815 if (s->val[option].s)
816 free (s->val[option].s);
817 s->val[option].s = strdup (val);
818 if (strcmp (s->val[OPT_PAPER].s, "User") != 0)
819 {
820 s->val[OPT_TL_X].w = 0;
821 s->val[OPT_TL_Y].w = 0;
822 if (strcmp (s->val[OPT_PAPER].s, "A3") == 0)
823 {
824 s->val[OPT_BR_X].w = PAPER_A3_W;
825 s->val[OPT_BR_Y].w = PAPER_A3_H;
826 }
827 else if (strcmp (s->val[OPT_PAPER].s, "A4") == 0)
828 {
829 s->val[OPT_BR_X].w = PAPER_A4_W;
830 s->val[OPT_BR_Y].w = PAPER_A4_H;
831 }
832 else if (strcmp (s->val[OPT_PAPER].s, "A4R") == 0)
833 {
834 s->val[OPT_BR_X].w = PAPER_A4R_W;
835 s->val[OPT_BR_Y].w = PAPER_A4R_H;
836 }
837 else if (strcmp (s->val[OPT_PAPER].s, "A5") == 0)
838 {
839 s->val[OPT_BR_X].w = PAPER_A5_W;
840 s->val[OPT_BR_Y].w = PAPER_A5_H;
841 }
842 else if (strcmp (s->val[OPT_PAPER].s, "A5R") == 0)
843 {
844 s->val[OPT_BR_X].w = PAPER_A5R_W;
845 s->val[OPT_BR_Y].w = PAPER_A5R_H;
846 }
847 else if (strcmp (s->val[OPT_PAPER].s, "A6") == 0)
848 {
849 s->val[OPT_BR_X].w = PAPER_A6_W;
850 s->val[OPT_BR_Y].w = PAPER_A6_H;
851 }
852 else if (strcmp (s->val[OPT_PAPER].s, "B4") == 0)
853 {
854 s->val[OPT_BR_X].w = PAPER_B4_W;
855 s->val[OPT_BR_Y].w = PAPER_B4_H;
856 }
857 else if (strcmp (s->val[OPT_PAPER].s, "Legal") == 0)
858 {
859 s->val[OPT_BR_X].w = PAPER_LEGAL_W;
860 s->val[OPT_BR_Y].w = PAPER_LEGAL_H;
861 }
862 else if (strcmp (s->val[OPT_PAPER].s, "Letter") == 0)
863 {
864 s->val[OPT_BR_X].w = PAPER_LETTER_W;
865 s->val[OPT_BR_Y].w = PAPER_LETTER_H;
866 }
867 }
868 return (SANE_STATUS_GOOD);
869 }
870
871 }
872 }
873
874 DBG (11, "<< sane_control_option\n");
875 return (SANE_STATUS_INVAL);
876 }
877
878 SANE_Status
sane_get_parameters(SANE_Handle handle, SANE_Parameters * params)879 sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
880 {
881 Ibm_Scanner *s = handle;
882 DBG (11, ">> sane_get_parameters\n");
883
884 if (!s->scanning)
885 {
886 int width, length, xres, yres;
887 const char *mode;
888
889 memset (&s->params, 0, sizeof (s->params));
890
891 width = s->val[OPT_BR_X].w - s->val[OPT_TL_X].w;
892 length = s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w;
893 xres = s->val[OPT_X_RESOLUTION].w;
894 yres = s->val[OPT_Y_RESOLUTION].w;
895
896 /* make best-effort guess at what parameters will look like once
897 scanning starts. */
898 if (xres > 0 && yres > 0 && width > 0 && length > 0)
899 {
900 s->params.pixels_per_line = width * xres / s->hw->info.mud;
901 s->params.lines = length * yres / s->hw->info.mud;
902 }
903
904 mode = s->val[OPT_MODE].s;
905 if ((strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) ||
906 (strcmp (mode, SANE_VALUE_SCAN_MODE_HALFTONE)) == 0)
907 {
908 s->params.format = SANE_FRAME_GRAY;
909 s->params.bytes_per_line = s->params.pixels_per_line / 8;
910 /* the Ibm truncates to the byte boundary, so: chop! */
911 s->params.pixels_per_line = s->params.bytes_per_line * 8;
912 s->params.depth = 1;
913 }
914 else /* if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) */
915 {
916 s->params.format = SANE_FRAME_GRAY;
917 s->params.bytes_per_line = s->params.pixels_per_line;
918 s->params.depth = 8;
919 }
920 s->params.last_frame = SANE_TRUE;
921 }
922 else
923 DBG (5, "sane_get_parameters: scanning, so can't get params\n");
924
925 if (params)
926 *params = s->params;
927
928 DBG (1, "%d pixels per line, %d bytes, %d lines high, total %lu bytes, "
929 "dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line,
930 s->params.lines, (u_long) s->bytes_to_read, s->val[OPT_Y_RESOLUTION].w);
931
932 DBG (11, "<< sane_get_parameters\n");
933 return (SANE_STATUS_GOOD);
934 }
935
936
937 SANE_Status
sane_start(SANE_Handle handle)938 sane_start (SANE_Handle handle)
939 {
940 char *mode_str;
941 Ibm_Scanner *s = handle;
942 SANE_Status status;
943 struct ibm_window_data wbuf;
944 struct measurements_units_page mup;
945
946 DBG (11, ">> sane_start\n");
947
948 /* First make sure we have a current parameter set. Some of the
949 parameters will be overwritten below, but that's OK. */
950 status = sane_get_parameters (s, 0);
951 if (status != SANE_STATUS_GOOD)
952 return status;
953
954 status = sanei_scsi_open (s->hw->sane.name, &s->fd, 0, 0);
955 if (status != SANE_STATUS_GOOD)
956 {
957 DBG (1, "open of %s failed: %s\n",
958 s->hw->sane.name, sane_strstatus (status));
959 return (status);
960 }
961
962 mode_str = s->val[OPT_MODE].s;
963 s->xres = s->val[OPT_X_RESOLUTION].w;
964 s->yres = s->val[OPT_Y_RESOLUTION].w;
965 s->ulx = s->val[OPT_TL_X].w;
966 s->uly = s->val[OPT_TL_Y].w;
967 s->width = s->val[OPT_BR_X].w - s->val[OPT_TL_X].w;
968 s->length = s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w;
969 s->brightness = s->val[OPT_BRIGHTNESS].w;
970 s->contrast = s->val[OPT_CONTRAST].w;
971 s->bpp = s->params.depth;
972 if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_LINEART) == 0)
973 {
974 s->image_composition = IBM_BINARY_MONOCHROME;
975 }
976 else if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_HALFTONE) == 0)
977 {
978 s->image_composition = IBM_DITHERED_MONOCHROME;
979 }
980 else if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_GRAY) == 0)
981 {
982 s->image_composition = IBM_GRAYSCALE;
983 }
984
985 memset (&wbuf, 0, sizeof (wbuf));
986 /* next line commented out by mf */
987 /* _lto2b(sizeof(wbuf) - 8, wbuf.len); */
988 /* next line by mf */
989 _lto2b(IBM_WINDOW_DATA_SIZE, wbuf.len); /* size=320 */
990 _lto2b(s->xres, wbuf.x_res);
991 _lto2b(s->yres, wbuf.y_res);
992 _lto4b(s->ulx, wbuf.x_org);
993 _lto4b(s->uly, wbuf.y_org);
994 _lto4b(s->width, wbuf.width);
995 _lto4b(s->length, wbuf.length);
996
997 wbuf.image_comp = s->image_composition;
998 /* if you throw the MRIF bit the brightness control reverses too */
999 /* so I reverse the reversal in software for symmetry's sake */
1000 if (wbuf.image_comp == IBM_GRAYSCALE || wbuf.image_comp == IBM_DITHERED_MONOCHROME)
1001 {
1002 if (wbuf.image_comp == IBM_GRAYSCALE)
1003 wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x80; /* it was 0x90 */
1004 if (wbuf.image_comp == IBM_DITHERED_MONOCHROME)
1005 wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x10;
1006 wbuf.brightness = 256 - (SANE_Byte) s->brightness;
1007 /*
1008 if (is50)
1009 wbuf.contrast = (SANE_Byte) s->contrast;
1010 else
1011 */
1012 wbuf.contrast = 256 - (SANE_Byte) s->contrast;
1013 }
1014 else /* wbuf.image_comp == IBM_BINARY_MONOCHROME */
1015 {
1016 wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x00;
1017 wbuf.brightness = (SANE_Byte) s->brightness;
1018 wbuf.contrast = (SANE_Byte) s->contrast;
1019 }
1020
1021 wbuf.threshold = 0;
1022 wbuf.bits_per_pixel = s->bpp;
1023
1024 wbuf.halftone_code = 2; /* diithering */
1025 wbuf.halftone_id = 0x0A; /* 8x8 Bayer pattenr */
1026 wbuf.pad_type = 3;
1027 wbuf.bit_ordering[0] = 0;
1028 wbuf.bit_ordering[1] = 7; /* modified by mf (it was 3) */
1029
1030 DBG (5, "xres=%d\n", _2btol(wbuf.x_res));
1031 DBG (5, "yres=%d\n", _2btol(wbuf.y_res));
1032 DBG (5, "ulx=%d\n", _4btol(wbuf.x_org));
1033 DBG (5, "uly=%d\n", _4btol(wbuf.y_org));
1034 DBG (5, "width=%d\n", _4btol(wbuf.width));
1035 DBG (5, "length=%d\n", _4btol(wbuf.length));
1036 DBG (5, "image_comp=%d\n", wbuf.image_comp);
1037
1038 DBG (11, "sane_start: sending SET WINDOW\n");
1039 status = set_window (s->fd, &wbuf);
1040 if (status != SANE_STATUS_GOOD)
1041 {
1042 DBG (1, "SET WINDOW failed: %s\n", sane_strstatus (status));
1043 return (status);
1044 }
1045
1046 DBG (11, "sane_start: sending GET WINDOW\n");
1047 memset (&wbuf, 0, sizeof (wbuf));
1048 status = get_window (s->fd, &wbuf);
1049 if (status != SANE_STATUS_GOOD)
1050 {
1051 DBG (1, "GET WINDOW failed: %s\n", sane_strstatus (status));
1052 return (status);
1053 }
1054 DBG (5, "xres=%d\n", _2btol(wbuf.x_res));
1055 DBG (5, "yres=%d\n", _2btol(wbuf.y_res));
1056 DBG (5, "ulx=%d\n", _4btol(wbuf.x_org));
1057 DBG (5, "uly=%d\n", _4btol(wbuf.y_org));
1058 DBG (5, "width=%d\n", _4btol(wbuf.width));
1059 DBG (5, "length=%d\n", _4btol(wbuf.length));
1060 DBG (5, "image_comp=%d\n", wbuf.image_comp);
1061
1062 DBG (11, "sane_start: sending MODE SELECT\n");
1063 memset (&mup, 0, sizeof (mup));
1064 mup.page_code = MEASUREMENTS_PAGE;
1065 mup.parameter_length = 0x06;
1066 mup.bmu = INCHES;
1067 mup.mud[0] = (DEFAULT_MUD >> 8) & 0xff;
1068 mup.mud[1] = (DEFAULT_MUD & 0xff);
1069 /* next lines by mf */
1070 mup.adf_page_code = 0x26;
1071 mup.adf_parameter_length = 6;
1072 if (s->adf_state == ADF_ARMED)
1073 mup.adf_control = 1;
1074 else
1075 mup.adf_control = 0;
1076 /* end lines by mf */
1077
1078 status = mode_select (s->fd, (struct mode_pages *) &mup);
1079 if (status != SANE_STATUS_GOOD)
1080 {
1081 DBG (1, "attach: MODE_SELECT failed\n");
1082 return (SANE_STATUS_INVAL);
1083 }
1084
1085 status = trigger_scan (s->fd);
1086 if (status != SANE_STATUS_GOOD)
1087 {
1088 DBG (1, "start of scan failed: %s\n", sane_strstatus (status));
1089 /* next line introduced not to freeze xscanimage */
1090 do_cancel(s);
1091 return status;
1092 }
1093
1094 /* Wait for scanner to become ready to transmit data */
1095 status = ibm_wait_ready (s);
1096 if (status != SANE_STATUS_GOOD)
1097 {
1098 DBG (1, "GET DATA STATUS failed: %s\n", sane_strstatus (status));
1099 return (status);
1100 }
1101
1102 s->bytes_to_read = s->params.bytes_per_line * s->params.lines;
1103
1104 DBG (1, "%d pixels per line, %d bytes, %d lines high, total %lu bytes, "
1105 "dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line,
1106 s->params.lines, (u_long) s->bytes_to_read, s->val[OPT_Y_RESOLUTION].w);
1107
1108 s->scanning = SANE_TRUE;
1109
1110 DBG (11, "<< sane_start\n");
1111 return (SANE_STATUS_GOOD);
1112 }
1113
1114 SANE_Status
sane_read(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len)1115 sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
1116 SANE_Int * len)
1117 {
1118 Ibm_Scanner *s = handle;
1119 SANE_Status status;
1120 size_t nread;
1121 DBG (11, ">> sane_read\n");
1122
1123 *len = 0;
1124
1125 DBG (11, "sane_read: bytes left to read: %ld\n", (u_long) s->bytes_to_read);
1126
1127 if (s->bytes_to_read == 0)
1128 {
1129 do_cancel (s);
1130 return (SANE_STATUS_EOF);
1131 }
1132
1133 if (!s->scanning) {
1134 DBG (11, "sane_read: scanning is false!\n");
1135 return (do_cancel (s));
1136 }
1137
1138 nread = max_len;
1139 if (nread > s->bytes_to_read)
1140 nread = s->bytes_to_read;
1141
1142 DBG (11, "sane_read: read %ld bytes\n", (u_long) nread);
1143 status = read_data (s->fd, buf, &nread);
1144 if (status != SANE_STATUS_GOOD)
1145 {
1146 DBG (11, "sane_read: read error\n");
1147 do_cancel (s);
1148 return (SANE_STATUS_IO_ERROR);
1149 }
1150 *len = nread;
1151 s->bytes_to_read -= nread;
1152
1153 DBG (11, "<< sane_read\n");
1154 return (SANE_STATUS_GOOD);
1155 }
1156
1157 void
sane_cancel(SANE_Handle handle)1158 sane_cancel (SANE_Handle handle)
1159 {
1160 Ibm_Scanner *s = handle;
1161 DBG (11, ">> sane_cancel\n");
1162
1163 s->scanning = SANE_FALSE;
1164
1165 DBG (11, "<< sane_cancel\n");
1166 }
1167
1168 SANE_Status
sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking)1169 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
1170 {
1171 DBG (5, ">> sane_set_io_mode (handle = %p, non_blocking = %d)\n",
1172 handle, non_blocking);
1173 DBG (5, "<< sane_set_io_mode\n");
1174
1175 return SANE_STATUS_UNSUPPORTED;
1176 }
1177
1178 SANE_Status
sane_get_select_fd(SANE_Handle handle, SANE_Int * fd)1179 sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
1180 {
1181 DBG (5, ">> sane_get_select_fd (handle = %p, fd = %p)\n",
1182 handle, (void *) fd);
1183 DBG (5, "<< sane_get_select_fd\n");
1184
1185 return SANE_STATUS_UNSUPPORTED;
1186 }
1187