1 /* HP Scanjet 3900 series - SANE Backend controller
2 Copyright (C) 2005-2009 Jonathan Bravo Lopez <jkdsoft@gmail.com>
3
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
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU 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
41 /* Backend Code for SANE*/
42 #define HP3900_CONFIG_FILE "hp3900.conf"
43 #define GAMMA_DEFAULT 1.0
44
45 #include "../include/sane/config.h"
46 #include "../include/sane/sane.h"
47 #include "../include/sane/sanei.h"
48 #include "../include/sane/sanei_backend.h"
49 #include "../include/sane/sanei_config.h"
50 #include "../include/sane/saneopts.h"
51 #include "../include/sane/sanei_usb.h"
52 #include "../include/sane/sanei_debug.h"
53
54 #include "hp3900_rts8822.c"
55
56 struct st_convert
57 {
58 SANE_Int colormode;
59 SANE_Int depth;
60 SANE_Int threshold;
61 SANE_Int negative;
62 SANE_Int real_depth;
63 };
64
65 /* options enumerator */
66 typedef enum
67 {
68 opt_begin = 0,
69
70 grp_geometry,
71 opt_tlx, opt_tly, opt_brx, opt_bry,
72 opt_resolution,
73
74 /* gamma tables */
75 opt_gamma_red,
76 opt_gamma_green,
77 opt_gamma_blue,
78
79 opt_scantype,
80 opt_colormode,
81 opt_depth,
82 opt_threshold,
83
84 /* debugging options */
85 grp_debug,
86 opt_model,
87 opt_negative,
88 opt_nogamma,
89 opt_nowshading,
90 opt_realdepth,
91 opt_emulategray,
92 opt_nowarmup,
93 opt_dbgimages,
94 opt_reset,
95
96 /* device information */
97 grp_info,
98 opt_chipname,
99 opt_chipid,
100 opt_scancount,
101 opt_infoupdate,
102
103 /* supported buttons. RTS8822 supports up to 6 buttons */
104 grp_sensors,
105 opt_button_0,
106 opt_button_1,
107 opt_button_2,
108 opt_button_3,
109 opt_button_4,
110 opt_button_5,
111
112 opt_count
113 } EOptionIndex;
114
115 /* linked list of SANE_Device structures */
116 typedef struct TDevListEntry
117 {
118 struct TDevListEntry *pNext;
119 SANE_Device dev;
120 char *devname;
121 } TDevListEntry;
122
123 typedef struct
124 {
125 char *pszVendor;
126 char *pszName;
127 } TScannerModel;
128
129 typedef union
130 {
131 SANE_Word w;
132 SANE_Word *wa; /* word array */
133 SANE_String s;
134 } TOptionValue;
135
136 typedef struct
137 {
138 SANE_Int model;
139 SANE_Option_Descriptor aOptions[opt_count];
140 TOptionValue aValues[opt_count];
141 struct params ScanParams;
142
143 /* lists */
144 SANE_String_Const *list_colormodes;
145 SANE_Int *list_depths;
146 SANE_String_Const *list_models;
147 SANE_Int *list_resolutions;
148 SANE_String_Const *list_sources;
149
150 SANE_Word *aGammaTable[3]; /* a 16-to-16 bit color lookup table */
151 SANE_Range rng_gamma;
152
153 /* reading image */
154 SANE_Byte *image;
155 SANE_Byte *rest;
156 SANE_Int rest_amount;
157 SANE_Int mylin;
158
159 /* conversion settings */
160 struct st_convert cnv;
161
162 /* ranges */
163 SANE_Range rng_threshold;
164 SANE_Range rng_horizontal;
165 SANE_Range rng_vertical;
166
167 SANE_Int scan_count;
168 SANE_Int fScanning; /* TRUE if actively scanning */
169 } TScanner;
170
171 /* functions to manage backend's options */
172 static void options_init (TScanner * scanner);
173 static void options_free (TScanner * scanner);
174
175 /* devices listing */
176 static SANE_Int _ReportDevice (TScannerModel * pModel,
177 const char *pszDeviceName);
178 static SANE_Status attach_one_device (SANE_String_Const devname);
179
180 /* capabilities */
181 static SANE_Status bknd_colormodes (TScanner * scanner, SANE_Int model);
182 static void bknd_constrains (TScanner * scanner, SANE_Int source,
183 SANE_Int type);
184 static SANE_Status bknd_depths (TScanner * scanner, SANE_Int model);
185 static SANE_Status bknd_info (TScanner * scanner);
186 static SANE_Status bknd_models (TScanner * scanner);
187 static SANE_Status bknd_resolutions (TScanner * scanner, SANE_Int model);
188 static SANE_Status bknd_sources (TScanner * scanner, SANE_Int model);
189
190 /* conversions */
191 static void Color_Negative (SANE_Byte * buffer, SANE_Int size,
192 SANE_Int depth);
193 static void Color_to_Gray (SANE_Byte * buffer, SANE_Int size, SANE_Int depth);
194 static void Gray_to_Lineart (SANE_Byte * buffer, SANE_Int size,
195 SANE_Int threshold);
196 static void Depth_16_to_8 (SANE_Byte * from_buffer, SANE_Int size,
197 SANE_Byte * to_buffer);
198
199 /* gamma functions */
200 static void gamma_apply (TScanner * s, SANE_Byte * buffer, SANE_Int size,
201 SANE_Int depth);
202 static SANE_Int gamma_create (TScanner * s, double gamma);
203 static void gamma_free (TScanner * s);
204
205 static SANE_Int Get_Colormode (SANE_String colormode);
206 static SANE_Int Get_Model (SANE_String model);
207 static SANE_Int Get_Source (SANE_String source);
208 static SANE_Int GetUSB_device_model (SANE_String_Const name);
209 static size_t max_string_size (const SANE_String_Const strings[]);
210
211 static SANE_Status get_button_status (TScanner * s);
212
213 /* reading buffers */
214 static SANE_Status img_buffers_alloc (TScanner * scanner, SANE_Int size);
215 static SANE_Status img_buffers_free (TScanner * scanner);
216
217 static SANE_Status option_get (TScanner * scanner, SANE_Int optid,
218 void *result);
219 static SANE_Status option_set (TScanner * scanner, SANE_Int optid,
220 void *value, SANE_Int * pInfo);
221
222 static void Set_Coordinates (SANE_Int scantype, SANE_Int resolution,
223 struct st_coords *coords);
224 static SANE_Int set_ScannerModel (SANE_Int proposed, SANE_Int product,
225 SANE_Int vendor);
226 static void Silent_Compile (void);
227 static SANE_Status Translate_coords (struct st_coords *coords);
228
229 /* SANE functions */
230 void sane_cancel (SANE_Handle h);
231 void sane_close (SANE_Handle h);
232 SANE_Status sane_control_option (SANE_Handle h, SANE_Int n,
233 SANE_Action Action, void *pVal,
234 SANE_Int * pInfo);
235 void sane_exit (void);
236 SANE_Status sane_get_devices (const SANE_Device *** device_list,
237 SANE_Bool local_only);
238 const SANE_Option_Descriptor *sane_get_option_descriptor (SANE_Handle h,
239 SANE_Int n);
240 SANE_Status sane_get_parameters (SANE_Handle h, SANE_Parameters * p);
241 SANE_Status sane_get_select_fd (SANE_Handle handle, SANE_Int * fd);
242 SANE_Status sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize);
243 SANE_Status sane_open (SANE_String_Const name, SANE_Handle * h);
244 SANE_Status sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen,
245 SANE_Int * len);
246 SANE_Status sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking);
247 SANE_Status sane_start (SANE_Handle h);
248
249 /* variables */
250 static struct st_device *device = NULL;
251 static TDevListEntry *_pFirstSaneDev = 0;
252 static SANE_Int iNumSaneDev = 0;
253 static const SANE_Device **_pSaneDevList = 0;
254
255 /* Own functions */
256
257 static SANE_Status
bknd_resolutions(TScanner * scanner,SANE_Int model)258 bknd_resolutions (TScanner * scanner, SANE_Int model)
259 {
260 SANE_Status rst = SANE_STATUS_INVAL;
261
262 DBG (DBG_FNC, "> bknd_resolutions(*scanner, model=%i)\n", model);
263
264 if (scanner != NULL)
265 {
266 SANE_Int *res = NULL;
267
268 switch (model)
269 {
270 case BQ5550:
271 case UA4900:
272 {
273 SANE_Int myres[] = { 8, 50, 75, 100, 150, 200, 300, 600, 1200 };
274
275 res = (SANE_Int *) malloc (sizeof (myres));
276 if (res != NULL)
277 memcpy (res, &myres, sizeof (myres));
278 }
279 break;
280
281 case HPG2710:
282 case HP3800:
283 {
284 /* 1200 and 2400 dpi are disabled until problems are solved */
285 SANE_Int myres[] = { 7, 50, 75, 100, 150, 200, 300, 600 };
286
287 res = (SANE_Int *) malloc (sizeof (myres));
288 if (res != NULL)
289 memcpy (res, &myres, sizeof (myres));
290 }
291 break;
292
293 case HP4370:
294 case HPG3010:
295 case HPG3110:
296 {
297 SANE_Int myres[] =
298 { 10, 50, 75, 100, 150, 200, 300, 600, 1200, 2400, 4800 };
299
300 res = (SANE_Int *) malloc (sizeof (myres));
301 if (res != NULL)
302 memcpy (res, &myres, sizeof (myres));
303 }
304 break;
305
306 default: /* HP3970 & HP4070 & UA4900 */
307 {
308 SANE_Int myres[] =
309 { 9, 50, 75, 100, 150, 200, 300, 600, 1200, 2400 };
310
311 res = (SANE_Int *) malloc (sizeof (myres));
312 if (res != NULL)
313 memcpy (res, &myres, sizeof (myres));
314 }
315 break;
316 }
317
318 if (res != NULL)
319 {
320 if (scanner->list_resolutions != NULL)
321 free (scanner->list_resolutions);
322
323 scanner->list_resolutions = res;
324 rst = SANE_STATUS_GOOD;
325 }
326 }
327
328 return rst;
329 }
330
331 static SANE_Status
bknd_models(TScanner * scanner)332 bknd_models (TScanner * scanner)
333 {
334 SANE_Status rst = SANE_STATUS_INVAL;
335
336 DBG (DBG_FNC, "> bknd_models:\n");
337
338 if (scanner != NULL)
339 {
340 SANE_String_Const *model = NULL;
341
342 /* at this moment all devices use the same list */
343 SANE_String_Const mymodel[] =
344 { "HP3800", "HP3970", "HP4070", "HP4370", "UA4900", "HPG3010",
345 "BQ5550", "HPG2710", "HPG3110", 0 };
346
347 /* allocate space to save list */
348 model = (SANE_String_Const *) malloc (sizeof (mymodel));
349 if (model != NULL)
350 memcpy (model, &mymodel, sizeof (mymodel));
351
352 if (model != NULL)
353 {
354 /* free previous list */
355 if (scanner->list_models != NULL)
356 free (scanner->list_models);
357
358 /* set new list */
359 scanner->list_models = model;
360 rst = SANE_STATUS_GOOD;
361 }
362 }
363
364 return rst;
365 }
366
367 static SANE_Status
bknd_colormodes(TScanner * scanner,SANE_Int model)368 bknd_colormodes (TScanner * scanner, SANE_Int model)
369 {
370 SANE_Status rst = SANE_STATUS_INVAL;
371
372 DBG (DBG_FNC, "> bknd_colormodes(*scanner, model=%i)\n", model);
373
374 if (scanner != NULL)
375 {
376 SANE_String_Const *colormode = NULL;
377
378 /* at this moment all devices use the same list */
379 SANE_String_Const mycolormode[] =
380 { SANE_VALUE_SCAN_MODE_COLOR, SANE_VALUE_SCAN_MODE_GRAY, SANE_VALUE_SCAN_MODE_LINEART, 0 };
381
382 /* silence gcc */
383 model = model;
384
385 colormode = (SANE_String_Const *) malloc (sizeof (mycolormode));
386 if (colormode != NULL)
387 memcpy (colormode, &mycolormode, sizeof (mycolormode));
388
389 if (colormode != NULL)
390 {
391 if (scanner->list_colormodes != NULL)
392 free (scanner->list_colormodes);
393
394 scanner->list_colormodes = colormode;
395 rst = SANE_STATUS_GOOD;
396 }
397 }
398
399 return rst;
400 }
401
402 static SANE_Status
bknd_sources(TScanner * scanner,SANE_Int model)403 bknd_sources (TScanner * scanner, SANE_Int model)
404 {
405 SANE_Status rst = SANE_STATUS_INVAL;
406
407 DBG (DBG_FNC, "> bknd_sources(*scanner, model=%i)\n", model);
408
409 if (scanner != NULL)
410 {
411 SANE_String_Const *source = NULL;
412
413 switch (model)
414 {
415 case UA4900:
416 {
417 SANE_String_Const mysource[] = { SANE_I18N ("Flatbed"), 0 };
418 source = (SANE_String_Const *) malloc (sizeof (mysource));
419 if (source != NULL)
420 memcpy (source, &mysource, sizeof (mysource));
421 }
422 break;
423 default: /* hp3970, hp4070, hp4370 and others */
424 {
425 SANE_String_Const mysource[] =
426 { SANE_I18N ("Flatbed"), SANE_I18N ("Slide"),
427 SANE_I18N ("Negative"), 0 };
428 source = (SANE_String_Const *) malloc (sizeof (mysource));
429 if (source != NULL)
430 memcpy (source, &mysource, sizeof (mysource));
431 }
432 break;
433 }
434
435 if (source != NULL)
436 {
437 if (scanner->list_sources != NULL)
438 free (scanner->list_sources);
439
440 scanner->list_sources = source;
441 rst = SANE_STATUS_GOOD;
442 }
443 }
444
445 return rst;
446 }
447
448 static SANE_Status
bknd_depths(TScanner * scanner,SANE_Int model)449 bknd_depths (TScanner * scanner, SANE_Int model)
450 {
451 SANE_Status rst = SANE_STATUS_INVAL;
452
453 DBG (DBG_FNC, "> bknd_depths(*scanner, model=%i\n", model);
454
455 if (scanner != NULL)
456 {
457 SANE_Int *depth = NULL;
458
459 /* at this moment all devices use the same list */
460 SANE_Int mydepth[] = { 2, 8, 16 }; /*{3, 8, 12, 16}; */
461
462 /* silence gcc */
463 model = model;
464
465 depth = (SANE_Int *) malloc (sizeof (mydepth));
466 if (depth != NULL)
467 memcpy (depth, &mydepth, sizeof (mydepth));
468
469 if (depth != NULL)
470 {
471 if (scanner->list_depths != NULL)
472 free (scanner->list_depths);
473
474 scanner->list_depths = depth;
475 rst = SANE_STATUS_GOOD;
476 }
477 }
478
479 return rst;
480 }
481
482 static SANE_Status
bknd_info(TScanner * scanner)483 bknd_info (TScanner * scanner)
484 {
485 SANE_Status rst = SANE_STATUS_INVAL;
486
487 DBG (DBG_FNC, "> bknd_info(*scanner)");
488
489 if (scanner != NULL)
490 {
491 char data[256];
492
493 /* update chipset name */
494 Chipset_Name (device, data, 255);
495 if (scanner->aValues[opt_chipname].s != NULL)
496 {
497 free (scanner->aValues[opt_chipname].s);
498 scanner->aValues[opt_chipname].s = NULL;
499 }
500
501 scanner->aValues[opt_chipname].s = strdup (data);
502 scanner->aOptions[opt_chipname].size = strlen (data) + 1;
503
504 /* update chipset id */
505 scanner->aValues[opt_chipid].w = Chipset_ID (device);
506
507 /* update scans counter */
508 scanner->aValues[opt_scancount].w = RTS_ScanCounter_Get (device);
509
510 rst = SANE_STATUS_GOOD;
511 }
512
513 return rst;
514 }
515
516 static SANE_Int
GetUSB_device_model(SANE_String_Const name)517 GetUSB_device_model (SANE_String_Const name)
518 {
519 SANE_Int usbid, model;
520
521 /* default model is unknown */
522 model = -1;
523
524 /* open usb device */
525 if (sanei_usb_open (name, &usbid) == SANE_STATUS_GOOD)
526 {
527 SANE_Int vendor, product;
528
529 if (sanei_usb_get_vendor_product (usbid, &vendor, &product) ==
530 SANE_STATUS_GOOD)
531 model = Device_get (product, vendor);
532
533 sanei_usb_close (usbid);
534 }
535
536 return model;
537 }
538
539 static void
Silent_Compile(void)540 Silent_Compile (void)
541 {
542 /*
543 There are some functions in hp3900_rts8822.c that aren't used yet.
544 To avoid compilation warnings we will use them here
545 */
546
547 SANE_Byte a = 1;
548
549 if (a == 0)
550 {
551 Buttons_Status (device);
552 Calib_WriteTable (device, NULL, 0, 0);
553 Gamma_GetTables (device, NULL);
554 }
555 }
556
557 static void
bknd_constrains(TScanner * scanner,SANE_Int source,SANE_Int type)558 bknd_constrains (TScanner * scanner, SANE_Int source, SANE_Int type)
559 {
560 struct st_coords *coords = Constrains_Get (device, source);
561
562 if ((coords != NULL) && (scanner != NULL))
563 {
564 switch (type)
565 {
566 case 1: /* Y */
567 scanner->rng_vertical.max = coords->height;
568 break;
569 default: /* X */
570 scanner->rng_horizontal.max = coords->width;
571 break;
572 }
573 }
574 }
575
576 static SANE_Status
img_buffers_free(TScanner * scanner)577 img_buffers_free (TScanner * scanner)
578 {
579 if (scanner != NULL)
580 {
581 if (scanner->image != NULL)
582 {
583 free (scanner->image);
584 scanner->image = NULL;
585 }
586
587 if (scanner->rest != NULL)
588 {
589 free (scanner->rest);
590 scanner->rest = NULL;
591 }
592
593 scanner->rest_amount = 0;
594 }
595
596 return SANE_STATUS_GOOD;
597 }
598
599 static SANE_Status
img_buffers_alloc(TScanner * scanner,SANE_Int size)600 img_buffers_alloc (TScanner * scanner, SANE_Int size)
601 {
602 SANE_Status rst;
603
604 /* default result at this point */
605 rst = SANE_STATUS_INVAL;
606
607 if (scanner != NULL)
608 {
609 /* default result at this point */
610 rst = SANE_STATUS_NO_MEM;
611
612 /* free previous allocs */
613 img_buffers_free (scanner);
614
615 scanner->image = (SANE_Byte *) malloc (size * sizeof (SANE_Byte));
616 if (scanner->image != NULL)
617 {
618 scanner->rest = (SANE_Byte *) malloc (size * sizeof (SANE_Byte));
619 if (scanner->rest != NULL)
620 rst = SANE_STATUS_GOOD; /* ok !! */
621 }
622
623 if (rst != SANE_STATUS_GOOD)
624 img_buffers_free (scanner);
625 }
626
627 return rst;
628 }
629
630 static SANE_Int
set_ScannerModel(SANE_Int proposed,SANE_Int product,SANE_Int vendor)631 set_ScannerModel (SANE_Int proposed, SANE_Int product, SANE_Int vendor)
632 {
633 /* This function will set the device behaviour */
634
635 SANE_Int current = Device_get (product, vendor);
636 char *sdevname[10] =
637 { "Unknown", "HP3970", "HP4070", "HP4370", "UA4900", "HP3800", "HPG3010",
638 "BQ5550", "HPG2710", "HPG3110" };
639
640 DBG (DBG_FNC,
641 "> set_ScannerModel(proposed=%i, product=%04x, vendor=%04x)\n",
642 proposed, product, vendor);
643
644 if (proposed < 0)
645 {
646 if ((current < 0) || (current >= DEVSCOUNT))
647 {
648 DBG (DBG_VRB, " -> Unknown device. Defaulting to HP3970...\n");
649 RTS_Debug->dev_model = HP3970;
650 }
651 else
652 {
653 RTS_Debug->dev_model = current;
654 DBG (DBG_VRB, " -> Device model is %s\n", sdevname[current + 1]);
655 }
656 }
657 else
658 {
659 if (proposed < DEVSCOUNT)
660 {
661 RTS_Debug->dev_model = proposed;
662 DBG (DBG_VRB, " -> Device %s , treating as %s ...\n",
663 sdevname[current + 1], sdevname[proposed + 1]);
664 }
665 else
666 {
667 if ((current >= 0) && (current < DEVSCOUNT))
668 {
669 RTS_Debug->dev_model = current;
670 DBG (DBG_VRB,
671 " -> Device not supported. Defaulting to %s ...\n",
672 sdevname[current + 1]);
673 }
674 else
675 {
676 RTS_Debug->dev_model = HP3970;
677 DBG (DBG_VRB,
678 "-> Device not supported. Defaulting to HP3970...\n");
679 }
680 }
681 }
682
683 return OK;
684 }
685
686 static void
Set_Coordinates(SANE_Int scantype,SANE_Int resolution,struct st_coords * coords)687 Set_Coordinates (SANE_Int scantype, SANE_Int resolution,
688 struct st_coords *coords)
689 {
690 struct st_coords *limits = Constrains_Get (device, scantype);
691
692 DBG (DBG_FNC, "> Set_Coordinates(res=%i, *coords):\n", resolution);
693
694 if (coords->left == -1)
695 coords->left = 0;
696
697 if (coords->width == -1)
698 coords->width = limits->width;
699
700 if (coords->top == -1)
701 coords->top = 0;
702
703 if (coords->height == -1)
704 coords->height = limits->height;
705
706 DBG (DBG_FNC, " -> Coords [MM] : xy(%i, %i) wh(%i, %i)\n", coords->left,
707 coords->top, coords->width, coords->height);
708
709 coords->left = MM_TO_PIXEL (coords->left, resolution);
710 coords->width = MM_TO_PIXEL (coords->width, resolution);
711 coords->top = MM_TO_PIXEL (coords->top, resolution);
712 coords->height = MM_TO_PIXEL (coords->height, resolution);
713
714 DBG (DBG_FNC, " -> Coords [px] : xy(%i, %i) wh(%i, %i)\n", coords->left,
715 coords->top, coords->width, coords->height);
716
717 Constrains_Check (device, resolution, scantype, coords);
718
719 DBG (DBG_FNC, " -> Coords [check]: xy(%i, %i) wh(%i, %i)\n", coords->left,
720 coords->top, coords->width, coords->height);
721 }
722
723 static void
Color_Negative(SANE_Byte * buffer,SANE_Int size,SANE_Int depth)724 Color_Negative (SANE_Byte * buffer, SANE_Int size, SANE_Int depth)
725 {
726 if (buffer != NULL)
727 {
728 SANE_Int a;
729 SANE_Int max_value = (1 << depth) - 1;
730
731 if (depth > 8)
732 {
733 USHORT *sColor = (void *) buffer;
734 for (a = 0; a < size / 2; a++)
735 {
736 *sColor = max_value - *sColor;
737 sColor++;
738 }
739 }
740 else
741 {
742 for (a = 0; a < size; a++)
743 *(buffer + a) = max_value - *(buffer + a);
744 }
745 }
746 }
747
748 static SANE_Status
get_button_status(TScanner * s)749 get_button_status (TScanner * s)
750 {
751 if (s != NULL)
752 {
753 SANE_Int a, b, status, btn;
754
755 b = 1;
756 status = Buttons_Released (device) & 63;
757 for (a = 0; a < 6; a++)
758 {
759 if ((status & b) != 0)
760 {
761 btn = Buttons_Order (device, b);
762 if (btn != -1)
763 s->aValues[opt_button_0 + btn].w = SANE_TRUE;
764 }
765
766 b <<= 1;
767 }
768 }
769
770 return SANE_STATUS_GOOD;
771 }
772
773 static void
Depth_16_to_8(SANE_Byte * from_buffer,SANE_Int size,SANE_Byte * to_buffer)774 Depth_16_to_8 (SANE_Byte * from_buffer, SANE_Int size, SANE_Byte * to_buffer)
775 {
776 if ((from_buffer != NULL) && (to_buffer != NULL))
777 {
778 SANE_Int a, b;
779
780 a = 1;
781 b = 0;
782
783 while (a < size)
784 {
785 *(to_buffer + b) = *(from_buffer + a);
786 a += 2;
787 b++;
788 }
789 }
790 }
791
792 static void
Gray_to_Lineart(SANE_Byte * buffer,SANE_Int size,SANE_Int threshold)793 Gray_to_Lineart (SANE_Byte * buffer, SANE_Int size, SANE_Int threshold)
794 {
795 /* code provided by tobias leutwein */
796
797 if (buffer != NULL)
798 {
799 SANE_Byte toBufferByte;
800 SANE_Int fromBufferPos_i = 0;
801 SANE_Int toBufferPos_i = 0;
802 SANE_Int bitPos_i;
803
804 while (fromBufferPos_i < size)
805 {
806 toBufferByte = 0;
807
808 for (bitPos_i = 7; bitPos_i != (-1); bitPos_i--)
809 {
810 if ((fromBufferPos_i < size)
811 && (buffer[fromBufferPos_i] < threshold))
812 toBufferByte |= (1u << bitPos_i);
813
814 fromBufferPos_i++;
815 }
816
817 buffer[toBufferPos_i] = toBufferByte;
818 toBufferPos_i++;
819 }
820 }
821 }
822
823 static void
Color_to_Gray(SANE_Byte * buffer,SANE_Int size,SANE_Int depth)824 Color_to_Gray (SANE_Byte * buffer, SANE_Int size, SANE_Int depth)
825 {
826 /* converts 3 color channel into 1 gray channel of specified bit depth */
827
828 if (buffer != NULL)
829 {
830 SANE_Int c, chn, chn_size;
831 SANE_Byte *ptr_src = NULL;
832 SANE_Byte *ptr_dst = NULL;
833 float data, chn_data;
834 float coef[3] = { 0.299, 0.587, 0.114 }; /* coefficients per channel */
835
836 chn_size = (depth > 8) ? 2 : 1;
837 ptr_src = (void *) buffer;
838 ptr_dst = (void *) buffer;
839
840 for (c = 0; c < size / (3 * chn_size); c++)
841 {
842 data = 0.;
843
844 /* get, apply coeffs and sum channels */
845 for (chn = 0; chn < 3; chn++)
846 {
847 chn_data = data_lsb_get (ptr_src + (chn * chn_size), chn_size);
848 data += (chn_data * coef[chn]);
849 }
850
851 /* save result */
852 data_lsb_set (ptr_dst, (SANE_Int) data, chn_size);
853
854 ptr_src += 3 * chn_size; /* next triplet */
855 ptr_dst += chn_size;
856 }
857 }
858 }
859
860 static void
gamma_free(TScanner * s)861 gamma_free (TScanner * s)
862 {
863 DBG (DBG_FNC, "> gamma_free()\n");
864
865 if (s != NULL)
866 {
867 /* Destroy gamma tables */
868 SANE_Int a;
869
870 for (a = CL_RED; a <= CL_BLUE; a++)
871 {
872 if (s->aGammaTable[a] != NULL)
873 {
874 free (s->aGammaTable[a]);
875 s->aGammaTable[a] = NULL;
876 }
877 }
878 }
879 }
880
881 static SANE_Int
gamma_create(TScanner * s,double gamma)882 gamma_create (TScanner * s, double gamma)
883 {
884 SANE_Int rst = ERROR; /* by default */
885
886 DBG (DBG_FNC, "> gamma_create(*s)\n");
887
888 if (s != NULL)
889 {
890 SANE_Int a;
891 double value, c;
892
893 /* default result */
894 rst = OK;
895
896 /* destroy previous gamma tables */
897 gamma_free (s);
898
899 /* check gamma value */
900 if (gamma < 0)
901 gamma = GAMMA_DEFAULT;
902
903 /* allocate space for 16 bit gamma tables */
904 for (a = CL_RED; a <= CL_BLUE; a++)
905 {
906 s->aGammaTable[a] = malloc (65536 * sizeof (SANE_Word));
907 if (s->aGammaTable[a] == NULL)
908 {
909 rst = ERROR;
910 break;
911 }
912 }
913
914 if (rst == OK)
915 {
916 /* fill tables */
917 for (a = 0; a < 65536; a++)
918 {
919 value = (a / (65536. - 1));
920 value = pow (value, (1. / gamma));
921 value = value * (65536. - 1);
922
923 c = (SANE_Int) value;
924 if (c > (65536. - 1))
925 c = (65536. - 1);
926 else if (c < 0)
927 c = 0;
928
929 s->aGammaTable[CL_RED][a] = c;
930 s->aGammaTable[CL_GREEN][a] = c;
931 s->aGammaTable[CL_BLUE][a] = c;
932 }
933 }
934 else
935 gamma_free (s);
936 }
937
938 return rst;
939 }
940
941 static void
gamma_apply(TScanner * s,SANE_Byte * buffer,SANE_Int size,SANE_Int depth)942 gamma_apply (TScanner * s, SANE_Byte * buffer, SANE_Int size, SANE_Int depth)
943 {
944 if ((s != NULL) && (buffer != NULL))
945 {
946 SANE_Int c;
947 SANE_Int dot_size = 3 * ((depth > 8) ? 2 : 1);
948 SANE_Byte *pColor = buffer;
949 USHORT *sColor = (void *) buffer;
950
951 if ((s->aGammaTable[CL_RED] != NULL)
952 && (s->aGammaTable[CL_GREEN] != NULL)
953 && (s->aGammaTable[CL_BLUE] != NULL))
954 {
955 for (c = 0; c < size / dot_size; c++)
956 {
957 if (depth > 8)
958 {
959 *sColor = s->aGammaTable[CL_RED][*sColor];
960 *(sColor + 1) = s->aGammaTable[CL_GREEN][*(sColor + 1)];
961 *(sColor + 2) = s->aGammaTable[CL_BLUE][*(sColor + 2)];
962 sColor += 3;
963 }
964 else
965 {
966 /* 8 bits gamma */
967 *pColor =
968 (s->aGammaTable[CL_RED][*pColor * 256] >> 8) & 0xff;
969 *(pColor + 1) =
970 (s->
971 aGammaTable[CL_GREEN][*(pColor + 1) * 256] >> 8) & 0xff;
972 *(pColor + 2) =
973 (s->
974 aGammaTable[CL_BLUE][*(pColor + 2) * 256] >> 8) & 0xff;
975 pColor += 3;
976 }
977 }
978 }
979 }
980 }
981
982 static SANE_Int
Get_Model(SANE_String model)983 Get_Model (SANE_String model)
984 {
985 SANE_Int rst;
986
987 if (strcmp (model, "HP3800") == 0)
988 rst = HP3800;
989 else if (strcmp (model, "HPG2710") == 0)
990 rst = HPG2710;
991 else if (strcmp (model, "HP3970") == 0)
992 rst = HP3970;
993 else if (strcmp (model, "HP4070") == 0)
994 rst = HP4070;
995 else if (strcmp (model, "HP4370") == 0)
996 rst = HP4370;
997 else if (strcmp (model, "HPG3010") == 0)
998 rst = HPG3010;
999 else if (strcmp (model, "HPG3110") == 0)
1000 rst = HPG3110;
1001 else if (strcmp (model, "UA4900") == 0)
1002 rst = UA4900;
1003 else if (strcmp (model, "BQ5550") == 0)
1004 rst = BQ5550;
1005 else
1006 rst = HP3970; /* default */
1007
1008 return rst;
1009 }
1010
1011 static SANE_Int
Get_Source(SANE_String source)1012 Get_Source (SANE_String source)
1013 {
1014 SANE_Int rst;
1015
1016 if (strcmp (source, SANE_I18N ("Flatbed")) == 0)
1017 rst = ST_NORMAL;
1018 else if (strcmp (source, SANE_I18N ("Slide")) == 0)
1019 rst = ST_TA;
1020 else if (strcmp (source, SANE_I18N ("Negative")) == 0)
1021 rst = ST_NEG;
1022 else
1023 rst = ST_NORMAL; /* default */
1024
1025 return rst;
1026 }
1027
1028 static SANE_Int
Get_Colormode(SANE_String colormode)1029 Get_Colormode (SANE_String colormode)
1030 {
1031 SANE_Int rst;
1032
1033 if (strcmp (colormode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1034 rst = CM_COLOR;
1035 else if (strcmp (colormode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1036 rst = CM_GRAY;
1037 else if (strcmp (colormode, SANE_VALUE_SCAN_MODE_LINEART) == 0)
1038 rst = CM_LINEART;
1039 else
1040 rst = CM_COLOR; /* default */
1041
1042 return rst;
1043 }
1044
1045 static SANE_Status
Translate_coords(struct st_coords * coords)1046 Translate_coords (struct st_coords *coords)
1047 {
1048 SANE_Int data;
1049
1050 DBG (DBG_FNC, "> Translate_coords(*coords)\n");
1051
1052 if ((coords->left < 0) || (coords->top < 0) ||
1053 (coords->width < 0) || (coords->height < 0))
1054 return SANE_STATUS_INVAL;
1055
1056 if (coords->width < coords->left)
1057 {
1058 data = coords->left;
1059 coords->left = coords->width;
1060 coords->width = data;
1061 }
1062
1063 if (coords->height < coords->top)
1064 {
1065 data = coords->top;
1066 coords->top = coords->height;
1067 coords->height = data;
1068 }
1069
1070 coords->width -= coords->left;
1071 coords->height -= coords->top;
1072
1073 if (coords->width == 0)
1074 coords->width++;
1075
1076 if (coords->height == 0)
1077 coords->height++;
1078
1079 return SANE_STATUS_GOOD;
1080 }
1081
1082 static size_t
max_string_size(const SANE_String_Const strings[])1083 max_string_size (const SANE_String_Const strings[])
1084 {
1085 size_t size, max_size = 0;
1086 SANE_Int i;
1087
1088 DBG (DBG_FNC, "> max_string_size:\n");
1089
1090 for (i = 0; strings[i]; ++i)
1091 {
1092 size = strlen (strings[i]) + 1;
1093 if (size > max_size)
1094 max_size = size;
1095 }
1096
1097 return max_size;
1098 }
1099
1100 static void
options_free(TScanner * scanner)1101 options_free (TScanner * scanner)
1102 {
1103 /* frees all information contained in controls */
1104
1105 DBG (DBG_FNC, "> options_free\n");
1106
1107 if (scanner != NULL)
1108 {
1109 SANE_Int i;
1110 SANE_Option_Descriptor *pDesc;
1111 TOptionValue *pVal;
1112
1113 /* free gamma tables */
1114 gamma_free (scanner);
1115
1116 /* free lists */
1117 if (scanner->list_resolutions != NULL)
1118 free (scanner->list_resolutions);
1119
1120 if (scanner->list_depths != NULL)
1121 free (scanner->list_depths);
1122
1123 if (scanner->list_sources != NULL)
1124 free (scanner->list_sources);
1125
1126 if (scanner->list_colormodes != NULL)
1127 free (scanner->list_colormodes);
1128
1129 if (scanner->list_models != NULL)
1130 free (scanner->list_models);
1131
1132 /* free values in certain controls */
1133 for (i = opt_begin; i < opt_count; i++)
1134 {
1135 pDesc = &scanner->aOptions[i];
1136 pVal = &scanner->aValues[i];
1137
1138 if (pDesc->type == SANE_TYPE_STRING)
1139 {
1140 if (pVal->s != NULL)
1141 free (pVal->s);
1142 }
1143 }
1144 }
1145 }
1146
1147 static void
options_init(TScanner * scanner)1148 options_init (TScanner * scanner)
1149 {
1150 /* initializes all controls */
1151
1152 DBG (DBG_FNC, "> options_init\n");
1153
1154 if (scanner != NULL)
1155 {
1156 SANE_Int i;
1157 SANE_Option_Descriptor *pDesc;
1158 TOptionValue *pVal;
1159
1160 /* set gamma */
1161 gamma_create (scanner, 1.0);
1162
1163 /* color conversion */
1164 scanner->cnv.colormode = -1;
1165 scanner->cnv.negative = FALSE;
1166 scanner->cnv.threshold = 40;
1167 scanner->cnv.real_depth = FALSE;
1168 scanner->cnv.depth = -1;
1169
1170 /* setting threshold */
1171 scanner->rng_threshold.min = 0;
1172 scanner->rng_threshold.max = 255;
1173 scanner->rng_threshold.quant = 0;
1174
1175 /* setting gamma range (16 bits depth) */
1176 scanner->rng_gamma.min = 0;
1177 scanner->rng_gamma.max = 65535;
1178 scanner->rng_gamma.quant = 0;
1179
1180 /* setting default horizontal constraint in millimeters */
1181 scanner->rng_horizontal.min = 0;
1182 scanner->rng_horizontal.max = 220;
1183 scanner->rng_horizontal.quant = 1;
1184
1185 /* setting default vertical constraint in millimeters */
1186 scanner->rng_vertical.min = 0;
1187 scanner->rng_vertical.max = 300;
1188 scanner->rng_vertical.quant = 1;
1189
1190 /* allocate option lists */
1191 bknd_info (scanner);
1192 bknd_colormodes (scanner, RTS_Debug->dev_model);
1193 bknd_depths (scanner, RTS_Debug->dev_model);
1194 bknd_models (scanner);
1195 bknd_resolutions (scanner, RTS_Debug->dev_model);
1196 bknd_sources (scanner, RTS_Debug->dev_model);
1197
1198 /* By default preview scan */
1199 scanner->ScanParams.scantype = ST_NORMAL;
1200 scanner->ScanParams.colormode = CM_COLOR;
1201 scanner->ScanParams.resolution_x = 75;
1202 scanner->ScanParams.resolution_y = 75;
1203 scanner->ScanParams.coords.left = 0;
1204 scanner->ScanParams.coords.top = 0;
1205 scanner->ScanParams.coords.width = 220;
1206 scanner->ScanParams.coords.height = 300;
1207 scanner->ScanParams.depth = 8;
1208 scanner->ScanParams.channel = 0;
1209
1210 for (i = opt_begin; i < opt_count; i++)
1211 {
1212 pDesc = &scanner->aOptions[i];
1213 pVal = &scanner->aValues[i];
1214
1215 /* defaults */
1216 pDesc->name = "";
1217 pDesc->title = "";
1218 pDesc->desc = "";
1219 pDesc->type = SANE_TYPE_INT;
1220 pDesc->unit = SANE_UNIT_NONE;
1221 pDesc->size = sizeof (SANE_Word);
1222 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1223 pDesc->cap = 0;
1224
1225 switch (i)
1226 {
1227 case opt_begin:
1228 pDesc->title = SANE_TITLE_NUM_OPTIONS;
1229 pDesc->desc = SANE_DESC_NUM_OPTIONS;
1230 pDesc->cap = SANE_CAP_SOFT_DETECT;
1231 pVal->w = (SANE_Word) opt_count;
1232 break;
1233
1234 case grp_geometry:
1235 pDesc->name = SANE_NAME_GEOMETRY;
1236 pDesc->title = SANE_TITLE_GEOMETRY;
1237 pDesc->desc = SANE_DESC_GEOMETRY;
1238 pDesc->type = SANE_TYPE_GROUP;
1239 pDesc->unit = SANE_UNIT_NONE;
1240 pDesc->size = 0;
1241 pDesc->cap = 0;
1242 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1243 pDesc->constraint.range = 0;
1244 pVal->w = 0;
1245 break;
1246
1247 case opt_tlx:
1248 pDesc->name = SANE_NAME_SCAN_TL_X;
1249 pDesc->title = SANE_TITLE_SCAN_TL_X;
1250 pDesc->desc = SANE_DESC_SCAN_TL_X;
1251 pDesc->unit = SANE_UNIT_MM;
1252 pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
1253 pDesc->constraint.range = &scanner->rng_horizontal;
1254 pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1255 pVal->w = 0;
1256 break;
1257
1258 case opt_tly:
1259 pDesc->name = SANE_NAME_SCAN_TL_Y;
1260 pDesc->title = SANE_TITLE_SCAN_TL_Y;
1261 pDesc->desc = SANE_DESC_SCAN_TL_Y;
1262 pDesc->unit = SANE_UNIT_MM;
1263 pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
1264 pDesc->constraint.range = &scanner->rng_vertical;
1265 pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1266 pVal->w = 0;
1267 break;
1268
1269 case opt_brx:
1270 pDesc->name = SANE_NAME_SCAN_BR_X;
1271 pDesc->title = SANE_TITLE_SCAN_BR_X;
1272 pDesc->desc = SANE_DESC_SCAN_BR_X;
1273 pDesc->unit = SANE_UNIT_MM;
1274 pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
1275 pDesc->constraint.range = &scanner->rng_horizontal;
1276 pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1277 pVal->w = scanner->rng_horizontal.max;
1278 break;
1279
1280 case opt_bry:
1281 pDesc->name = SANE_NAME_SCAN_BR_Y;
1282 pDesc->title = SANE_TITLE_SCAN_BR_Y;
1283 pDesc->desc = SANE_DESC_SCAN_BR_Y;
1284 pDesc->unit = SANE_UNIT_MM;
1285 pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
1286 pDesc->constraint.range = &scanner->rng_vertical;
1287 pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1288 pVal->w = scanner->rng_vertical.max;
1289 break;
1290
1291 case opt_resolution:
1292 pDesc->name = SANE_NAME_SCAN_RESOLUTION;
1293 pDesc->title = SANE_TITLE_SCAN_RESOLUTION;
1294 pDesc->desc = SANE_DESC_SCAN_RESOLUTION;
1295 pDesc->unit = SANE_UNIT_DPI;
1296 pDesc->constraint_type = SANE_CONSTRAINT_WORD_LIST;
1297 pDesc->constraint.word_list = scanner->list_resolutions;
1298 pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1299 pVal->w = scanner->list_resolutions[1];
1300 break;
1301
1302 case opt_gamma_red:
1303 pDesc->name = SANE_NAME_GAMMA_VECTOR_R;
1304 pDesc->title = SANE_TITLE_GAMMA_VECTOR_R;
1305 pDesc->desc = SANE_DESC_GAMMA_VECTOR_R;
1306 pDesc->size = scanner->rng_gamma.max * sizeof (SANE_Word);
1307 pDesc->unit = SANE_UNIT_NONE;
1308 pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
1309 pDesc->constraint.range = &scanner->rng_gamma;
1310 pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1311 pVal->wa = scanner->aGammaTable[CL_RED];
1312 break;
1313
1314 case opt_gamma_green:
1315 pDesc->name = SANE_NAME_GAMMA_VECTOR_G;
1316 pDesc->title = SANE_TITLE_GAMMA_VECTOR_G;
1317 pDesc->desc = SANE_DESC_GAMMA_VECTOR_G;
1318 pDesc->size = scanner->rng_gamma.max * sizeof (SANE_Word);
1319 pDesc->unit = SANE_UNIT_NONE;
1320 pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
1321 pDesc->constraint.range = &scanner->rng_gamma;
1322 pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1323 pVal->wa = scanner->aGammaTable[CL_GREEN];
1324 break;
1325
1326 case opt_gamma_blue:
1327 pDesc->name = SANE_NAME_GAMMA_VECTOR_B;
1328 pDesc->title = SANE_TITLE_GAMMA_VECTOR_B;
1329 pDesc->desc = SANE_DESC_GAMMA_VECTOR_B;
1330 pDesc->size = scanner->rng_gamma.max * sizeof (SANE_Word);
1331 pDesc->unit = SANE_UNIT_NONE;
1332 pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
1333 pDesc->constraint.range = &scanner->rng_gamma;
1334 pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1335 pVal->wa = scanner->aGammaTable[CL_BLUE];
1336 break;
1337
1338 case opt_scantype:
1339 pDesc->name = SANE_NAME_SCAN_SOURCE;
1340 pDesc->title = SANE_TITLE_SCAN_SOURCE;
1341 pDesc->desc = SANE_DESC_SCAN_SOURCE;
1342 pDesc->type = SANE_TYPE_STRING;
1343 pDesc->size = max_string_size (scanner->list_sources);
1344 pDesc->constraint_type = SANE_CONSTRAINT_STRING_LIST;
1345 pDesc->constraint.string_list = scanner->list_sources;
1346 pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1347 pVal->s = strdup (scanner->list_sources[0]);
1348 break;
1349
1350 case opt_colormode:
1351 pDesc->name = SANE_NAME_SCAN_MODE;
1352 pDesc->title = SANE_TITLE_SCAN_MODE;
1353 pDesc->desc = SANE_DESC_SCAN_MODE;
1354 pDesc->type = SANE_TYPE_STRING;
1355 pDesc->size = max_string_size (scanner->list_colormodes);
1356 pDesc->constraint_type = SANE_CONSTRAINT_STRING_LIST;
1357 pDesc->constraint.string_list = scanner->list_colormodes;
1358 pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1359 pVal->s = strdup (scanner->list_colormodes[0]);
1360 break;
1361
1362 case opt_depth:
1363 pDesc->name = SANE_NAME_BIT_DEPTH;
1364 pDesc->title = SANE_TITLE_BIT_DEPTH;
1365 pDesc->desc = SANE_DESC_BIT_DEPTH;
1366 pDesc->type = SANE_TYPE_INT;
1367 pDesc->unit = SANE_UNIT_BIT;
1368 pDesc->constraint_type = SANE_CONSTRAINT_WORD_LIST;
1369 pDesc->constraint.word_list = scanner->list_depths;
1370 pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1371 pVal->w = scanner->list_depths[1];
1372 break;
1373
1374 case opt_threshold:
1375 pDesc->name = SANE_NAME_THRESHOLD;
1376 pDesc->title = SANE_TITLE_THRESHOLD;
1377 pDesc->desc = SANE_DESC_THRESHOLD;
1378 pDesc->type = SANE_TYPE_INT;
1379 pDesc->unit = SANE_UNIT_NONE;
1380 pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
1381 pDesc->constraint.range = &scanner->rng_threshold;
1382 pDesc->cap |=
1383 SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT |
1384 SANE_CAP_INACTIVE;
1385 pVal->w = 0x80;
1386 break;
1387
1388 /* debugging options */
1389 case grp_debug:
1390 pDesc->name = "grp_debug";
1391 pDesc->title = SANE_I18N ("Debugging Options");
1392 pDesc->desc = "";
1393 pDesc->type = SANE_TYPE_GROUP;
1394 pDesc->unit = SANE_UNIT_NONE;
1395 pDesc->size = 0;
1396 pDesc->cap = SANE_CAP_ADVANCED;
1397 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1398 pDesc->constraint.range = 0;
1399 pVal->w = 0;
1400 break;
1401
1402 case opt_model:
1403 pDesc->name = "opt_model";
1404 pDesc->title = SANE_I18N ("Scanner model");
1405 pDesc->desc =
1406 SANE_I18N
1407 ("Allows one to test device behavior with other supported models");
1408 pDesc->type = SANE_TYPE_STRING;
1409 pDesc->size = max_string_size (scanner->list_models);
1410 pDesc->constraint_type = SANE_CONSTRAINT_STRING_LIST;
1411 pDesc->constraint.string_list = scanner->list_models;
1412 pDesc->cap =
1413 SANE_CAP_ADVANCED | SANE_CAP_SOFT_SELECT |
1414 SANE_CAP_SOFT_DETECT;
1415 pVal->s = strdup (scanner->list_models[0]);
1416 break;
1417
1418 case opt_negative:
1419 pDesc->name = "opt_negative";
1420 pDesc->title = SANE_I18N ("Negative");
1421 pDesc->desc = SANE_I18N ("Image colors will be inverted");
1422 pDesc->type = SANE_TYPE_BOOL;
1423 pDesc->unit = SANE_UNIT_NONE;
1424 pDesc->size = sizeof (SANE_Word);
1425 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1426 pDesc->constraint.range = 0;
1427 pDesc->cap =
1428 SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
1429 SANE_CAP_SOFT_SELECT;
1430 pVal->w = SANE_FALSE;
1431 break;
1432
1433 case opt_nogamma:
1434 pDesc->name = "opt_nogamma";
1435 pDesc->title = SANE_I18N ("Disable gamma correction");
1436 pDesc->desc = SANE_I18N ("Gamma correction will be disabled");
1437 pDesc->type = SANE_TYPE_BOOL;
1438 pDesc->unit = SANE_UNIT_NONE;
1439 pDesc->size = sizeof (SANE_Word);
1440 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1441 pDesc->constraint.range = 0;
1442 pDesc->cap =
1443 SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
1444 SANE_CAP_SOFT_SELECT;
1445 pVal->w = SANE_FALSE;
1446 break;
1447
1448 case opt_nowshading:
1449 pDesc->name = "opt_nowshading";
1450 pDesc->title = SANE_I18N ("Disable white shading correction");
1451 pDesc->desc =
1452 SANE_I18N ("White shading correction will be disabled");
1453 pDesc->type = SANE_TYPE_BOOL;
1454 pDesc->unit = SANE_UNIT_NONE;
1455 pDesc->size = sizeof (SANE_Word);
1456 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1457 pDesc->constraint.range = 0;
1458 pDesc->cap =
1459 SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
1460 SANE_CAP_SOFT_SELECT;
1461 pVal->w = SANE_FALSE;
1462 break;
1463
1464 case opt_nowarmup:
1465 pDesc->name = "opt_nowarmup";
1466 pDesc->title = SANE_I18N ("Skip warmup process");
1467 pDesc->desc = SANE_I18N ("Warmup process will be disabled");
1468 pDesc->type = SANE_TYPE_BOOL;
1469 pDesc->unit = SANE_UNIT_NONE;
1470 pDesc->size = sizeof (SANE_Word);
1471 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1472 pDesc->constraint.range = 0;
1473 pDesc->cap =
1474 SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
1475 SANE_CAP_SOFT_SELECT;
1476 pVal->w = SANE_FALSE;
1477 break;
1478
1479 case opt_realdepth:
1480 pDesc->name = "opt_realdepth";
1481 pDesc->title = SANE_I18N ("Force real depth");
1482 pDesc->desc =
1483 SANE_I18N
1484 ("If gamma is enabled, scans are always made in 16 bits depth to improve image quality and then converted to the selected depth. This option avoids depth emulation.");
1485 pDesc->type = SANE_TYPE_BOOL;
1486 pDesc->unit = SANE_UNIT_NONE;
1487 pDesc->size = sizeof (SANE_Word);
1488 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1489 pDesc->constraint.range = 0;
1490 pDesc->cap =
1491 SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
1492 SANE_CAP_SOFT_SELECT;
1493 pVal->w = SANE_FALSE;
1494 break;
1495
1496 case opt_emulategray:
1497 pDesc->name = "opt_emulategray";
1498 pDesc->title = SANE_I18N ("Emulate Grayscale");
1499 pDesc->desc =
1500 SANE_I18N
1501 ("If enabled, image will be scanned in color mode and then converted to grayscale by software. This may improve image quality in some circumstances.");
1502 pDesc->type = SANE_TYPE_BOOL;
1503 pDesc->unit = SANE_UNIT_NONE;
1504 pDesc->size = sizeof (SANE_Word);
1505 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1506 pDesc->constraint.range = 0;
1507 pDesc->cap =
1508 SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
1509 SANE_CAP_SOFT_SELECT;
1510 pVal->w = SANE_FALSE;
1511 break;
1512
1513 case opt_dbgimages:
1514 pDesc->name = "opt_dbgimages";
1515 pDesc->title = SANE_I18N ("Save debugging images");
1516 pDesc->desc =
1517 SANE_I18N
1518 ("If enabled, some images involved in scanner processing are saved to analyze them.");
1519 pDesc->type = SANE_TYPE_BOOL;
1520 pDesc->unit = SANE_UNIT_NONE;
1521 pDesc->size = sizeof (SANE_Word);
1522 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1523 pDesc->constraint.range = 0;
1524 pDesc->cap =
1525 SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT |
1526 SANE_CAP_SOFT_SELECT;
1527 pVal->w = SANE_FALSE;
1528 break;
1529
1530 case opt_reset:
1531 pDesc->name = "opt_reset";
1532 pDesc->title = SANE_I18N ("Reset chipset");
1533 pDesc->desc = SANE_I18N ("Resets chipset data");
1534 pDesc->type = SANE_TYPE_BUTTON;
1535 pDesc->unit = SANE_UNIT_NONE;
1536 pDesc->size = 0;
1537 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1538 pDesc->constraint.string_list = 0;
1539 pDesc->cap = SANE_CAP_ADVANCED | SANE_CAP_SOFT_SELECT;
1540 pVal->w = 0;
1541 break;
1542
1543 /* device information */
1544 case grp_info:
1545 pDesc->name = "grp_info";
1546 pDesc->title = SANE_I18N ("Information");
1547 pDesc->desc = "";
1548 pDesc->type = SANE_TYPE_GROUP;
1549 pDesc->unit = SANE_UNIT_NONE;
1550 pDesc->size = 0;
1551 pDesc->cap = 0;
1552 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1553 pDesc->constraint.range = 0;
1554 pVal->w = 0;
1555 break;
1556
1557 case opt_chipname:
1558 pDesc->name = "opt_chipname";
1559 pDesc->title = SANE_I18N ("Chipset name");
1560 pDesc->desc = SANE_I18N ("Shows chipset name used in device.");
1561 pDesc->type = SANE_TYPE_STRING;
1562 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1563 pDesc->cap = SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT;
1564 pVal->s = strdup (SANE_I18N ("Unknown"));
1565 pDesc->size = strlen(pVal->s) + 1;
1566 break;
1567
1568 case opt_chipid:
1569 pDesc->name = "opt_chipid";
1570 pDesc->title = SANE_I18N ("Chipset ID");
1571 pDesc->desc = SANE_I18N ("Shows the chipset ID");
1572 pDesc->type = SANE_TYPE_INT;
1573 pDesc->unit = SANE_UNIT_NONE;
1574 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1575 pDesc->cap = SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT;
1576 pVal->w = -1;
1577 break;
1578
1579 case opt_scancount:
1580 pDesc->name = "opt_scancount";
1581 pDesc->title = SANE_I18N ("Scan counter");
1582 pDesc->desc =
1583 SANE_I18N ("Shows the number of scans made by scanner");
1584 pDesc->type = SANE_TYPE_INT;
1585 pDesc->unit = SANE_UNIT_NONE;
1586 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1587 pDesc->cap = SANE_CAP_ADVANCED | SANE_CAP_SOFT_DETECT;
1588 pVal->w = -1;
1589 break;
1590
1591 case opt_infoupdate:
1592 pDesc->name = "opt_infoupdate";
1593 pDesc->title = SANE_I18N ("Update information");
1594 pDesc->desc = SANE_I18N ("Updates information about device");
1595 pDesc->type = SANE_TYPE_BUTTON;
1596 pDesc->unit = SANE_UNIT_NONE;
1597 pDesc->size = 0;
1598 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1599 pDesc->constraint.string_list = 0;
1600 pDesc->cap = SANE_CAP_ADVANCED | SANE_CAP_SOFT_SELECT;
1601 pVal->w = 0;
1602 break;
1603
1604 /* buttons support */
1605 case grp_sensors:
1606 pDesc->name = SANE_NAME_SENSORS;
1607 pDesc->title = SANE_TITLE_SENSORS;
1608 pDesc->desc = SANE_DESC_SENSORS;
1609 pDesc->type = SANE_TYPE_GROUP;
1610 pDesc->unit = SANE_UNIT_NONE;
1611 pDesc->size = 0;
1612 pDesc->cap = 0;
1613 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1614 pDesc->constraint.range = 0;
1615 pVal->w = 0;
1616 break;
1617
1618 case opt_button_0:
1619 case opt_button_1:
1620 case opt_button_2:
1621 case opt_button_3:
1622 case opt_button_4:
1623 case opt_button_5:
1624 {
1625 char name[12];
1626 char title[128];
1627
1628 sprintf (name, "button %d", i - opt_button_0);
1629 sprintf (title, "Scanner button %d", i - opt_button_0);
1630 pDesc->name = strdup (name);
1631 pDesc->title = strdup (title);
1632 pDesc->desc =
1633 SANE_I18N
1634 ("This option reflects a front panel scanner button");
1635 pDesc->type = SANE_TYPE_BOOL;
1636 pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
1637
1638 if (i - opt_button_0 >= Buttons_Count (device))
1639 pDesc->cap |= SANE_CAP_INACTIVE;
1640
1641 pDesc->unit = SANE_UNIT_NONE;
1642 pDesc->size = sizeof (SANE_Word);
1643 pDesc->constraint_type = SANE_CONSTRAINT_NONE;
1644 pVal->w = SANE_FALSE;
1645 }
1646 break;
1647 }
1648 }
1649 }
1650 }
1651
1652 static SANE_Int
_ReportDevice(TScannerModel * pModel,const char * pszDeviceName)1653 _ReportDevice (TScannerModel * pModel, const char *pszDeviceName)
1654 {
1655 SANE_Int rst = ERROR;
1656 TDevListEntry *pNew, *pDev;
1657
1658 DBG (DBG_FNC, "> _ReportDevice:\n");
1659
1660 pNew = malloc (sizeof (TDevListEntry));
1661 if (pNew != NULL)
1662 {
1663 rst = OK;
1664
1665 /* add new element to the end of the list */
1666 if (_pFirstSaneDev != NULL)
1667 {
1668 /* Add at the end of existing list */
1669 for (pDev = _pFirstSaneDev; pDev->pNext; pDev = pDev->pNext);
1670
1671 pDev->pNext = pNew;
1672 }
1673 else
1674 _pFirstSaneDev = pNew;
1675
1676 /* fill in new element */
1677 pNew->pNext = NULL;
1678 pNew->devname = (char *) strdup (pszDeviceName);
1679 pNew->dev.name = pNew->devname;
1680 pNew->dev.vendor = pModel->pszVendor;
1681 pNew->dev.model = pModel->pszName;
1682 pNew->dev.type = SANE_I18N ("flatbed scanner");
1683
1684 iNumSaneDev++;
1685 }
1686
1687 return rst;
1688 }
1689
1690 static SANE_Status
attach_one_device(SANE_String_Const devname)1691 attach_one_device (SANE_String_Const devname)
1692 {
1693 static TScannerModel sModel;
1694
1695 DBG (DBG_FNC, "> attach_one_device(devname=%s)\n", devname);
1696
1697 switch (GetUSB_device_model (devname))
1698 {
1699 case HP3800:
1700 sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
1701 sModel.pszName = (char *) strdup ("Scanjet 3800");
1702 break;
1703 case HPG2710:
1704 sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
1705 sModel.pszName = (char *) strdup ("Scanjet G2710");
1706 break;
1707 case HP3970:
1708 sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
1709 sModel.pszName = (char *) strdup ("Scanjet 3970");
1710 break;
1711 case HP4070:
1712 sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
1713 sModel.pszName = (char *) strdup ("Scanjet 4070 Photosmart");
1714 break;
1715 case HP4370:
1716 sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
1717 sModel.pszName = (char *) strdup ("Scanjet 4370");
1718 break;
1719 case HPG3010:
1720 sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
1721 sModel.pszName = (char *) strdup ("Scanjet G3010");
1722 break;
1723 case HPG3110:
1724 sModel.pszVendor = (char *) strdup ("Hewlett-Packard");
1725 sModel.pszName = (char *) strdup ("Scanjet G3110");
1726 break;
1727 case UA4900:
1728 sModel.pszVendor = (char *) strdup ("UMAX");
1729 sModel.pszName = (char *) strdup ("Astra 4900");
1730 break;
1731 case BQ5550:
1732 sModel.pszVendor = (char *) strdup ("BenQ");
1733 sModel.pszName = (char *) strdup ("5550");
1734 break;
1735 default:
1736 sModel.pszVendor = (char *) strdup ("Unknown");
1737 sModel.pszName = (char *) strdup ("RTS8822 chipset based");
1738 break;
1739 }
1740
1741 _ReportDevice (&sModel, devname);
1742
1743 return SANE_STATUS_GOOD;
1744 }
1745
1746 /* Sane default functions */
1747
1748 SANE_Status
sane_init(SANE_Int * version_code,SANE_Auth_Callback authorize)1749 sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
1750 {
1751 FILE *conf_fp; /* Config file stream */
1752 SANE_Char line[PATH_MAX];
1753 SANE_Char *str = NULL;
1754 SANE_String_Const proper_str;
1755 SANE_Int nline = 0;
1756
1757 /* Initialize debug */
1758 DBG_INIT ();
1759
1760 DBG (DBG_FNC, "> sane_init\n");
1761
1762 /* silence gcc */
1763 authorize = authorize;
1764
1765 /* Initialize usb */
1766 sanei_usb_init ();
1767
1768 /* Parse config file */
1769 conf_fp = sanei_config_open (HP3900_CONFIG_FILE);
1770 if (conf_fp)
1771 {
1772 while (sanei_config_read (line, sizeof (line), conf_fp))
1773 {
1774 nline++;
1775 if (str)
1776 free (str);
1777
1778 proper_str = sanei_config_get_string (line, &str);
1779
1780 /* Discards white lines and comments */
1781 if ((str != NULL) && (proper_str != line) && (str[0] != '#'))
1782 {
1783 /* If line's not blank or a comment, then it's the device
1784 * filename or a usb directive. */
1785 sanei_usb_attach_matching_devices (line, attach_one_device);
1786 }
1787 }
1788 fclose (conf_fp);
1789 }
1790 else
1791 {
1792 /* default */
1793 DBG (DBG_VRB, "- %s not found. Looking for hardcoded usb ids ...\n",
1794 HP3900_CONFIG_FILE);
1795
1796 sanei_usb_attach_matching_devices ("usb 0x03f0 0x2605", attach_one_device); /* HP3800 */
1797 sanei_usb_attach_matching_devices ("usb 0x03f0 0x2805", attach_one_device); /* HPG2710 */
1798 sanei_usb_attach_matching_devices ("usb 0x03f0 0x2305", attach_one_device); /* HP3970 */
1799 sanei_usb_attach_matching_devices ("usb 0x03f0 0x2405", attach_one_device); /* HP4070 */
1800 sanei_usb_attach_matching_devices ("usb 0x03f0 0x4105", attach_one_device); /* HP4370 */
1801 sanei_usb_attach_matching_devices ("usb 0x03f0 0x4205", attach_one_device); /* HPG3010 */
1802 sanei_usb_attach_matching_devices ("usb 0x03f0 0x4305", attach_one_device); /* HPG3110 */
1803 sanei_usb_attach_matching_devices ("usb 0x06dc 0x0020", attach_one_device); /* UA4900 */
1804 sanei_usb_attach_matching_devices ("usb 0x04a5 0x2211", attach_one_device); /* BQ5550 */
1805 }
1806
1807 /* Return backend version */
1808 if (version_code != NULL)
1809 *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, 0);
1810
1811 return SANE_STATUS_GOOD;
1812 }
1813
1814 SANE_Status
sane_get_devices(const SANE_Device *** device_list,SANE_Bool local_only)1815 sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
1816 {
1817 SANE_Status rst = SANE_STATUS_GOOD;
1818
1819 local_only = local_only;
1820
1821 if (_pSaneDevList)
1822 free (_pSaneDevList);
1823
1824 _pSaneDevList = malloc (sizeof (*_pSaneDevList) * (iNumSaneDev + 1));
1825 if (_pSaneDevList != NULL)
1826 {
1827 TDevListEntry *pDev;
1828 SANE_Int i = 0;
1829
1830 for (pDev = _pFirstSaneDev; pDev; pDev = pDev->pNext)
1831 _pSaneDevList[i++] = &pDev->dev;
1832
1833 _pSaneDevList[i++] = 0; /* last entry is 0 */
1834 *device_list = _pSaneDevList;
1835 }
1836 else
1837 rst = SANE_STATUS_NO_MEM;
1838
1839 DBG (DBG_FNC, "> sane_get_devices: %i\n", rst);
1840
1841 return rst;
1842 }
1843
1844 SANE_Status
sane_open(SANE_String_Const name,SANE_Handle * h)1845 sane_open (SANE_String_Const name, SANE_Handle * h)
1846 {
1847 TScanner *s;
1848 SANE_Status rst;
1849
1850 /* check the name */
1851 if (strlen (name) == 0)
1852 /* default to first available device */
1853 name = _pFirstSaneDev->dev.name;
1854
1855 /* allocate space for RTS environment */
1856 device = RTS_Alloc ();
1857 if (device != NULL)
1858 {
1859 /* Open device */
1860 rst = sanei_usb_open (name, &device->usb_handle);
1861 if (rst == SANE_STATUS_GOOD)
1862 {
1863 /* Allocating memory for device */
1864 s = malloc (sizeof (TScanner));
1865 if (s != NULL)
1866 {
1867 memset (s, 0, sizeof (TScanner));
1868
1869 /* Initializing RTS */
1870 if (Init_Vars () == OK)
1871 {
1872 SANE_Int vendor, product;
1873
1874 /* Setting device model */
1875 if (sanei_usb_get_vendor_product
1876 (device->usb_handle, &vendor,
1877 &product) == SANE_STATUS_GOOD)
1878 s->model = Device_get (product, vendor);
1879 else
1880 s->model = HP3970;
1881
1882 set_ScannerModel (s->model, product, vendor);
1883
1884 /* Initialize device */
1885 if (RTS_Scanner_Init (device) == OK)
1886 {
1887 /* silencing unused functions */
1888 Silent_Compile ();
1889
1890 /* initialize backend options */
1891 options_init (s);
1892 *h = s;
1893
1894 /* everything went ok */
1895 rst = SANE_STATUS_GOOD;
1896 }
1897 else
1898 {
1899 free ((void *) s);
1900 rst = SANE_STATUS_INVAL;
1901 }
1902 }
1903 else
1904 rst = SANE_STATUS_NO_MEM;
1905 }
1906 else
1907 rst = SANE_STATUS_NO_MEM;
1908 }
1909 }
1910 else
1911 rst = SANE_STATUS_NO_MEM;
1912
1913 DBG (DBG_FNC, "> sane_open(name=%s): %i\n", name, rst);
1914
1915 return rst;
1916 }
1917
1918 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle h,SANE_Int n)1919 sane_get_option_descriptor (SANE_Handle h, SANE_Int n)
1920 {
1921 SANE_Option_Descriptor *rst = NULL;
1922
1923 if ((n >= opt_begin) && (n < opt_count))
1924 {
1925 TScanner *s = (TScanner *) h;
1926 rst = &s->aOptions[n];
1927 }
1928
1929 DBG (DBG_FNC, "> SANE_Option_Descriptor(handle, n=%i): %i\n", n,
1930 (rst == NULL) ? -1 : 0);
1931
1932 return rst;
1933 }
1934
1935 static SANE_Status
option_get(TScanner * scanner,SANE_Int optid,void * result)1936 option_get (TScanner * scanner, SANE_Int optid, void *result)
1937 {
1938 /* This function returns value contained in selected option */
1939
1940 DBG (DBG_FNC, "> option_get(optid=%i)\n", optid);
1941
1942 if ((scanner != NULL) && (result != NULL))
1943 {
1944 switch (optid)
1945 {
1946 /* SANE_Word */
1947 case opt_begin: /* null */
1948 case opt_reset: /* null */
1949 case opt_negative:
1950 case opt_nogamma:
1951 case opt_nowshading:
1952 case opt_emulategray:
1953 case opt_dbgimages:
1954 case opt_nowarmup:
1955 case opt_realdepth:
1956 case opt_depth:
1957 case opt_resolution:
1958 case opt_threshold:
1959 case opt_brx:
1960 case opt_tlx:
1961 case opt_bry:
1962 case opt_tly:
1963 *(SANE_Word *) result = scanner->aValues[optid].w;
1964 break;
1965
1966 /* SANE_Int */
1967 case opt_chipid:
1968 case opt_scancount:
1969 *(SANE_Int *) result = scanner->aValues[optid].w;
1970 break;
1971
1972 /* SANE_Word array */
1973 case opt_gamma_red:
1974 case opt_gamma_green:
1975 case opt_gamma_blue:
1976 memcpy (result, scanner->aValues[optid].wa,
1977 scanner->aOptions[optid].size);
1978 break;
1979
1980 /* String */
1981 case opt_colormode:
1982 case opt_scantype:
1983 case opt_model:
1984 case opt_chipname:
1985 strncpy (result, scanner->aValues[optid].s, scanner->aOptions[optid].size);
1986 ((char*)result)[scanner->aOptions[optid].size-1] = '\0';
1987
1988 break;
1989
1990 /* scanner buttons */
1991 case opt_button_0:
1992 get_button_status (scanner);
1993 // fall through
1994 case opt_button_1:
1995 case opt_button_2:
1996 case opt_button_3:
1997 case opt_button_4:
1998 case opt_button_5:
1999 /* copy the button state */
2000 *(SANE_Word *) result = scanner->aValues[optid].w;
2001 /* clear the button state */
2002 scanner->aValues[optid].w = SANE_FALSE;
2003 break;
2004 }
2005 }
2006
2007 return SANE_STATUS_GOOD;
2008 }
2009
2010 static SANE_Status
option_set(TScanner * scanner,SANE_Int optid,void * value,SANE_Int * pInfo)2011 option_set (TScanner * scanner, SANE_Int optid, void *value, SANE_Int * pInfo)
2012 {
2013 SANE_Status rst;
2014
2015 DBG (DBG_FNC, "> option_set(optid=%i)\n", optid);
2016
2017 rst = SANE_STATUS_INVAL;
2018
2019 if (scanner != NULL)
2020 {
2021 if (scanner->fScanning == FALSE)
2022 {
2023 SANE_Int info = 0;
2024
2025 rst = SANE_STATUS_GOOD;
2026
2027 switch (optid)
2028 {
2029 case opt_brx:
2030 case opt_tlx:
2031 case opt_bry:
2032 case opt_tly:
2033 case opt_depth:
2034 case opt_nogamma:
2035 case opt_nowshading:
2036 case opt_nowarmup:
2037 case opt_negative:
2038 case opt_emulategray:
2039 case opt_dbgimages:
2040 case opt_threshold:
2041 case opt_resolution:
2042 info |= SANE_INFO_RELOAD_PARAMS;
2043 scanner->aValues[optid].w = *(SANE_Word *) value;
2044 break;
2045
2046 case opt_gamma_red:
2047 case opt_gamma_green:
2048 case opt_gamma_blue:
2049 memcpy (scanner->aValues[optid].wa, value,
2050 scanner->aOptions[optid].size);
2051 break;
2052
2053 case opt_scantype:
2054 if (strcmp (scanner->aValues[optid].s, value) != 0)
2055 {
2056 struct st_coords *coords;
2057 SANE_Int source;
2058
2059 if (scanner->aValues[optid].s)
2060 free (scanner->aValues[optid].s);
2061
2062 scanner->aValues[optid].s = strdup (value);
2063
2064 source = Get_Source (scanner->aValues[opt_scantype].s);
2065 coords = Constrains_Get (device, source);
2066 if (coords != NULL)
2067 {
2068 bknd_constrains (scanner, source, 0);
2069 bknd_constrains (scanner, source, 1);
2070 scanner->aValues[opt_tlx].w = 0;
2071 scanner->aValues[opt_tly].w = 0;
2072 scanner->aValues[opt_brx].w = coords->width;
2073 scanner->aValues[opt_bry].w = coords->height;
2074 }
2075
2076 info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
2077 }
2078 break;
2079
2080 case opt_colormode:
2081 if (strcmp (scanner->aValues[optid].s, value) != 0)
2082 {
2083 if (scanner->aValues[optid].s)
2084 free (scanner->aValues[optid].s);
2085 scanner->aValues[optid].s = strdup (value);
2086 if (Get_Colormode (scanner->aValues[optid].s) == CM_LINEART)
2087 scanner->aOptions[opt_threshold].cap &=
2088 ~SANE_CAP_INACTIVE;
2089 else
2090 scanner->aOptions[opt_threshold].cap |= SANE_CAP_INACTIVE;
2091 info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
2092 }
2093 break;
2094
2095 case opt_model:
2096 if (strcmp (scanner->aValues[optid].s, value) != 0)
2097 {
2098 SANE_Int model;
2099
2100 if (scanner->aValues[optid].s)
2101 free (scanner->aValues[optid].s);
2102 scanner->aValues[optid].s = strdup (value);
2103
2104 model = Get_Model (scanner->aValues[optid].s);
2105 if (model != RTS_Debug->dev_model)
2106 {
2107 SANE_Int source;
2108 struct st_coords *coords;
2109
2110 /* free configuration of last model */
2111 Free_Config (device);
2112
2113 /* set new model */
2114 RTS_Debug->dev_model = model;
2115
2116 /* and load configuration of current model */
2117 Load_Config (device);
2118
2119 /* update options according to selected device */
2120 bknd_info (scanner);
2121 bknd_colormodes (scanner, model);
2122 bknd_depths (scanner, model);
2123 bknd_resolutions (scanner, model);
2124 bknd_sources (scanner, model);
2125
2126 /* updating lists */
2127 scanner->aOptions[opt_colormode].size =
2128 max_string_size (scanner->list_colormodes);
2129 scanner->aOptions[opt_colormode].constraint.
2130 string_list = scanner->list_colormodes;
2131 scanner->aOptions[opt_depth].constraint.word_list =
2132 scanner->list_depths;
2133 scanner->aOptions[opt_resolution].constraint.word_list =
2134 scanner->list_resolutions;
2135 scanner->aOptions[opt_scantype].size =
2136 max_string_size (scanner->list_sources);
2137 scanner->aOptions[opt_scantype].constraint.string_list =
2138 scanner->list_sources;
2139
2140 /* default values */
2141 if (scanner->aValues[opt_colormode].s != NULL)
2142 free (scanner->aValues[opt_colormode].s);
2143
2144 if (scanner->aValues[opt_scantype].s != NULL)
2145 free (scanner->aValues[opt_scantype].s);
2146
2147 scanner->aValues[opt_colormode].s =
2148 strdup (scanner->list_colormodes[0]);
2149 scanner->aValues[opt_scantype].s =
2150 strdup (scanner->list_sources[0]);
2151 scanner->aValues[opt_resolution].w =
2152 scanner->list_resolutions[1];
2153 scanner->aValues[opt_depth].w = scanner->list_depths[1];
2154
2155 source = Get_Source (scanner->aValues[opt_scantype].s);
2156 coords = Constrains_Get (device, source);
2157 if (coords != NULL)
2158 {
2159 bknd_constrains (scanner, source, 0);
2160 bknd_constrains (scanner, source, 1);
2161 scanner->aValues[opt_tlx].w = 0;
2162 scanner->aValues[opt_tly].w = 0;
2163 scanner->aValues[opt_brx].w = coords->width;
2164 scanner->aValues[opt_bry].w = coords->height;
2165 }
2166 }
2167
2168 info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
2169 }
2170 break;
2171
2172 case opt_reset:
2173 Chipset_Reset (device);
2174 break;
2175
2176 case opt_realdepth:
2177 scanner->aValues[optid].w =
2178 (scanner->cnv.real_depth == TRUE) ? SANE_TRUE : SANE_FALSE;
2179 break;
2180
2181 case opt_infoupdate:
2182 if (bknd_info (scanner) == SANE_STATUS_GOOD)
2183 info |= SANE_INFO_RELOAD_OPTIONS;
2184 break;
2185
2186 default:
2187 rst = SANE_STATUS_INVAL;
2188 break;
2189 }
2190
2191 if (pInfo != NULL)
2192 *pInfo = info;
2193 }
2194 }
2195
2196 return rst;
2197 }
2198
2199 SANE_Status
sane_control_option(SANE_Handle h,SANE_Int n,SANE_Action Action,void * pVal,SANE_Int * pInfo)2200 sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
2201 void *pVal, SANE_Int * pInfo)
2202 {
2203 TScanner *scanner;
2204 SANE_Status rst;
2205
2206 DBG (DBG_FNC, "> sane_control_option\n");
2207
2208 scanner = (TScanner *) h;
2209
2210 switch (Action)
2211 {
2212 case SANE_ACTION_GET_VALUE:
2213 rst = option_get (scanner, n, pVal);
2214 break;
2215
2216 case SANE_ACTION_SET_VALUE:
2217 rst = option_set (scanner, n, pVal, pInfo);
2218 break;
2219
2220 case SANE_ACTION_SET_AUTO:
2221 rst = SANE_STATUS_UNSUPPORTED;
2222 break;
2223
2224 default:
2225 rst = SANE_STATUS_INVAL;
2226 break;
2227 }
2228
2229 return rst;
2230 }
2231
2232 SANE_Status
sane_get_parameters(SANE_Handle h,SANE_Parameters * p)2233 sane_get_parameters (SANE_Handle h, SANE_Parameters * p)
2234 {
2235 SANE_Status rst = SANE_STATUS_INVAL;
2236 TScanner *s = (TScanner *) h;
2237
2238 DBG (DBG_FNC, "+ sane_get_parameters:");
2239
2240 if (s != NULL)
2241 {
2242 struct st_coords coords;
2243 SANE_Int res, source, depth, colormode, frameformat, bpl;
2244
2245 /* first do some checks */
2246
2247 /* colormode */
2248 colormode = Get_Colormode (s->aValues[opt_colormode].s);
2249
2250 /* frameformat */
2251 frameformat =
2252 (colormode == CM_COLOR) ? SANE_FRAME_RGB : SANE_FRAME_GRAY;
2253
2254 /* depth */
2255 depth = (colormode == CM_LINEART) ? 1 : s->aValues[opt_depth].w;
2256
2257 /* scan type */
2258 source = Get_Source (s->aValues[opt_scantype].s);
2259
2260 /* resolution */
2261 res = s->aValues[opt_resolution].w;
2262
2263 /* image coordinates in millimeters */
2264 coords.left = s->aValues[opt_tlx].w;
2265 coords.top = s->aValues[opt_tly].w;
2266 coords.width = s->aValues[opt_brx].w;
2267 coords.height = s->aValues[opt_bry].w;
2268
2269 /* validate coords */
2270 if (Translate_coords (&coords) == SANE_STATUS_GOOD)
2271 {
2272 Set_Coordinates (source, res, &coords);
2273
2274 if (colormode != CM_LINEART)
2275 {
2276 bpl = coords.width * ((depth > 8) ? 2 : 1);
2277 if (colormode == CM_COLOR)
2278 bpl *= 3; /* three channels */
2279 }
2280 else
2281 bpl = (coords.width + 7) / 8;
2282
2283 /* return the data */
2284 p->format = frameformat;
2285 p->last_frame = SANE_TRUE;
2286 p->depth = depth;
2287 p->lines = coords.height;
2288 p->pixels_per_line = coords.width;
2289 p->bytes_per_line = bpl;
2290
2291 DBG (DBG_FNC, " -> Depth : %i\n", depth);
2292 DBG (DBG_FNC, " -> Height: %i\n", coords.height);
2293 DBG (DBG_FNC, " -> Width : %i\n", coords.width);
2294 DBG (DBG_FNC, " -> BPL : %i\n", bpl);
2295
2296 rst = SANE_STATUS_GOOD;
2297 }
2298 }
2299
2300 DBG (DBG_FNC, "- sane_get_parameters: %i\n", rst);
2301
2302 return rst;
2303 }
2304
2305 SANE_Status
sane_start(SANE_Handle h)2306 sane_start (SANE_Handle h)
2307 {
2308 SANE_Status rst = SANE_STATUS_INVAL;
2309 TScanner *s;
2310
2311 DBG (DBG_FNC, "+ sane_start\n");
2312
2313 s = (TScanner *) h;
2314 if (s != NULL)
2315 {
2316 struct st_coords coords;
2317 SANE_Int res, source, colormode, depth, channel;
2318
2319 /* first do some checks */
2320 /* Get Scan type */
2321 source = Get_Source (s->aValues[opt_scantype].s);
2322
2323 /* Check if scanner supports slides and negatives in case selected source is tma */
2324 if (!((source != ST_NORMAL) && (RTS_isTmaAttached (device) == FALSE)))
2325 {
2326 /* Get depth */
2327 depth = s->aValues[opt_depth].w;
2328
2329 /* Get color mode */
2330 colormode = Get_Colormode (s->aValues[opt_colormode].s);
2331
2332 /* Emulating certain color modes */
2333 if (colormode == CM_LINEART)
2334 {
2335 /* emulate lineart */
2336 s->cnv.colormode = CM_LINEART;
2337 colormode = CM_GRAY;
2338 depth = 8;
2339 }
2340 else if ((colormode == CM_GRAY)
2341 && (s->aValues[opt_emulategray].w == SANE_TRUE))
2342 {
2343 /* emulate grayscale */
2344 s->cnv.colormode = CM_GRAY;
2345 colormode = CM_COLOR;
2346 }
2347 else
2348 s->cnv.colormode = -1;
2349
2350 /* setting channel for colormodes different than CM_COLOR */
2351 channel = (colormode != CM_COLOR) ? 1 : 0;
2352
2353 /* negative colors */
2354 s->cnv.negative =
2355 (s->aValues[opt_negative].w == SANE_TRUE) ? TRUE : FALSE;
2356
2357 /* Get threshold */
2358 s->cnv.threshold = s->aValues[opt_threshold].w;
2359
2360 /* Get resolution */
2361 res = s->aValues[opt_resolution].w;
2362
2363 /* set depth emulation */
2364 if (s->cnv.colormode == CM_LINEART)
2365 s->cnv.real_depth = TRUE;
2366 else
2367 s->cnv.real_depth =
2368 (s->aValues[opt_realdepth].w == SANE_TRUE) ? TRUE : FALSE;
2369
2370 /* use gamma? */
2371 RTS_Debug->EnableGamma =
2372 (s->aValues[opt_nogamma].w == SANE_TRUE) ? FALSE : TRUE;
2373
2374 /* disable white shading correction? */
2375 RTS_Debug->wshading =
2376 (s->aValues[opt_nowshading].w == SANE_TRUE) ? FALSE : TRUE;
2377
2378 /* skip warmup process? */
2379 RTS_Debug->warmup =
2380 (s->aValues[opt_nowarmup].w == SANE_TRUE) ? FALSE : TRUE;
2381
2382 /* save debugging images? */
2383 RTS_Debug->SaveCalibFile =
2384 (s->aValues[opt_dbgimages].w == SANE_TRUE) ? TRUE : FALSE;
2385
2386 /* Get image coordinates in millimeters */
2387 coords.left = s->aValues[opt_tlx].w;
2388 coords.top = s->aValues[opt_tly].w;
2389 coords.width = s->aValues[opt_brx].w;
2390 coords.height = s->aValues[opt_bry].w;
2391
2392 /* Validate coords */
2393 if (Translate_coords (&coords) == SANE_STATUS_GOOD)
2394 {
2395
2396 /* Stop previusly started scan */
2397 RTS_Scanner_StopScan (device, TRUE);
2398
2399 s->ScanParams.scantype = source;
2400 s->ScanParams.colormode = colormode;
2401 s->ScanParams.resolution_x = res;
2402 s->ScanParams.resolution_y = res;
2403 s->ScanParams.channel = channel;
2404
2405 memcpy (&s->ScanParams.coords, &coords,
2406 sizeof (struct st_coords));
2407 Set_Coordinates (source, res, &s->ScanParams.coords);
2408
2409 /* emulating depth? */
2410 if ((s->cnv.real_depth == FALSE) && (depth < 16)
2411 && (RTS_Debug->EnableGamma == TRUE))
2412 {
2413 /* In order to improve image quality, we will scan at 16bits if
2414 we are using gamma correction */
2415 s->cnv.depth = depth;
2416 s->ScanParams.depth = 16;
2417 }
2418 else
2419 {
2420 s->ScanParams.depth = depth;
2421 s->cnv.depth = -1;
2422 }
2423
2424 /* set scanning parameters */
2425 if (RTS_Scanner_SetParams (device, &s->ScanParams) == OK)
2426 {
2427 /* Start scanning process */
2428 if (RTS_Scanner_StartScan (device) == OK)
2429 {
2430 /* Allocate buffer to read one line */
2431 s->mylin = 0;
2432 rst = img_buffers_alloc (s, bytesperline);
2433 }
2434 }
2435 }
2436 }
2437 else
2438 rst = SANE_STATUS_COVER_OPEN;
2439 }
2440
2441 DBG (DBG_FNC, "- sane_start: %i\n", rst);
2442
2443 return rst;
2444 }
2445
2446 SANE_Status
sane_read(SANE_Handle h,SANE_Byte * buf,SANE_Int maxlen,SANE_Int * len)2447 sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len)
2448 {
2449 SANE_Status rst = SANE_STATUS_GOOD;
2450 TScanner *s = (TScanner *) h;
2451
2452 DBG (DBG_FNC, "+ sane_read\n");
2453
2454 if ((s != NULL) && (buf != NULL) && (len != NULL))
2455 {
2456 /* nothing has been read at the moment */
2457 *len = 0;
2458
2459 /* if we read all the lines return EOF */
2460 if ((s->mylin == s->ScanParams.coords.height)
2461 || (device->status->cancel == TRUE))
2462 {
2463 rst =
2464 (device->status->cancel ==
2465 TRUE) ? SANE_STATUS_CANCELLED : SANE_STATUS_EOF;
2466
2467 RTS_Scanner_StopScan (device, FALSE);
2468 img_buffers_free (s);
2469 }
2470 else
2471 {
2472 SANE_Int emul_len, emul_maxlen;
2473 SANE_Int thwidth, transferred, bufflength;
2474 SANE_Byte *buffer, *pbuffer;
2475
2476 emul_len = 0;
2477 if (s->cnv.depth != -1)
2478 emul_maxlen = maxlen * (s->ScanParams.depth / s->cnv.depth);
2479 else
2480 emul_maxlen = maxlen;
2481
2482 /* if grayscale emulation is enabled check that retrieved data is multiple of three */
2483 if (s->cnv.colormode == CM_GRAY)
2484 {
2485 SANE_Int chn_size, rest;
2486
2487 chn_size = (s->ScanParams.depth > 8) ? 2 : 1;
2488 rest = emul_maxlen % (3 * chn_size);
2489
2490 if (rest != 0)
2491 emul_maxlen -= rest;
2492 }
2493
2494 /* this is important to keep lines alignment in lineart mode */
2495 if (s->cnv.colormode == CM_LINEART)
2496 emul_maxlen = s->ScanParams.coords.width;
2497
2498 /* if we are emulating depth, we scan at 16bit when frontend waits
2499 for 8bit data. Next buffer will be used to retrieve data from
2500 scanner prior to convert to 8 bits depth */
2501 buffer = (SANE_Byte *) malloc (emul_maxlen * sizeof (SANE_Byte));
2502
2503 if (buffer != NULL)
2504 {
2505 pbuffer = buffer;
2506
2507 /* get bytes per line */
2508 if (s->ScanParams.colormode != CM_LINEART)
2509 {
2510 thwidth =
2511 s->ScanParams.coords.width *
2512 ((s->ScanParams.depth > 8) ? 2 : 1);
2513
2514 if (s->ScanParams.colormode == CM_COLOR)
2515 thwidth *= 3; /* three channels */
2516 }
2517 else
2518 thwidth = (s->ScanParams.coords.width + 7) / 8;
2519
2520 /* read as many lines the buffer may contain and while there are lines to be read */
2521 while ((emul_len < emul_maxlen)
2522 && (s->mylin < s->ScanParams.coords.height))
2523 {
2524 /* Is there any data waiting for being passed ? */
2525 if (s->rest_amount != 0)
2526 {
2527 /* copy to buffer as many bytes as we can */
2528 bufflength =
2529 min (emul_maxlen - emul_len, s->rest_amount);
2530 memcpy (pbuffer, s->rest, bufflength);
2531 emul_len += bufflength;
2532 pbuffer += bufflength;
2533 s->rest_amount -= bufflength;
2534 if (s->rest_amount == 0)
2535 s->mylin++;
2536 }
2537 else
2538 {
2539 /* read from scanner up to one line */
2540 if (Read_Image
2541 (device, bytesperline, s->image,
2542 &transferred) != OK)
2543 {
2544 /* error, exit function */
2545 rst = SANE_STATUS_EOF;
2546 break;
2547 }
2548
2549 /* is there any data? */
2550 if (transferred != 0)
2551 {
2552 /* copy to buffer as many bytes as we can */
2553 bufflength = min (emul_maxlen - emul_len, thwidth);
2554
2555 memcpy (pbuffer, s->image, bufflength);
2556 emul_len += bufflength;
2557 pbuffer += bufflength;
2558
2559 /* the rest will be copied to s->rest buffer */
2560 if (bufflength < thwidth)
2561 {
2562 s->rest_amount = thwidth - bufflength;
2563 memcpy (s->rest, s->image + bufflength,
2564 s->rest_amount);
2565 }
2566 else
2567 s->mylin++;
2568 }
2569 else
2570 break;
2571 }
2572 } /* while */
2573
2574 /* process buffer before sending to frontend */
2575 if ((emul_len > 0) && (rst != SANE_STATUS_EOF))
2576 {
2577 /* at this point ...
2578 buffer : contains retrieved image
2579 emul_len: contains size in bytes of retrieved image
2580
2581 after this code ...
2582 buf : will contain postprocessed image
2583 len : will contain size in bytes of postprocessed image */
2584
2585 /* apply gamma if necessary */
2586 if (RTS_Debug->EnableGamma == TRUE)
2587 gamma_apply (s, buffer, emul_len, s->ScanParams.depth);
2588
2589 /* if we are scanning negatives, let's invert colors */
2590 if (s->ScanParams.scantype == ST_NEG)
2591 {
2592 if (s->cnv.negative == FALSE)
2593 Color_Negative (buffer, emul_len,
2594 s->ScanParams.depth);
2595 }
2596 else if (s->cnv.negative != FALSE)
2597 Color_Negative (buffer, emul_len, s->ScanParams.depth);
2598
2599 /* emulating grayscale ? */
2600 if (s->cnv.colormode == CM_GRAY)
2601 {
2602 Color_to_Gray (buffer, emul_len, s->ScanParams.depth);
2603 emul_len /= 3;
2604 }
2605
2606 /* emulating depth */
2607 if (s->cnv.depth != -1)
2608 {
2609 switch (s->cnv.depth)
2610 {
2611 /* case 1: treated separately as lineart */
2612 /*case 12: in the future */
2613 case 8:
2614 Depth_16_to_8 (buffer, emul_len, buffer);
2615 emul_len /= 2;
2616 break;
2617 }
2618 }
2619
2620 /* lineart mode ? */
2621 if (s->cnv.colormode == CM_LINEART)
2622 {
2623 /* I didn't see any scanner supporting lineart mode.
2624 Windows drivers scan in grayscale and then convert image to lineart
2625 so let's perform conversion */
2626 SANE_Int rest = emul_len % 8;
2627
2628 Gray_to_Lineart (buffer, emul_len, s->cnv.threshold);
2629 emul_len /= 8;
2630 if (rest > 0)
2631 emul_len++;
2632 }
2633
2634 /* copy postprocessed image */
2635 *len = emul_len;
2636 memcpy (buf, buffer, *len);
2637 }
2638
2639 free (buffer);
2640 }
2641 }
2642 }
2643 else
2644 rst = SANE_STATUS_EOF;
2645
2646 DBG (DBG_FNC, "- sane_read: %s\n", sane_strstatus (rst));
2647
2648 return rst;
2649 }
2650
2651 void
sane_cancel(SANE_Handle h)2652 sane_cancel (SANE_Handle h)
2653 {
2654 DBG (DBG_FNC, "> sane_cancel\n");
2655
2656 /* silence gcc */
2657 h = h;
2658
2659 device->status->cancel = TRUE;
2660 }
2661
2662 SANE_Status
sane_set_io_mode(SANE_Handle handle,SANE_Bool non_blocking)2663 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
2664 {
2665 DBG (DBG_FNC, "> sane_set_io_mode\n");
2666
2667 /* silence gcc */
2668 handle = handle;
2669 non_blocking = non_blocking;
2670
2671 return SANE_STATUS_UNSUPPORTED;
2672 }
2673
2674 SANE_Status
sane_get_select_fd(SANE_Handle handle,SANE_Int * fd)2675 sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
2676 {
2677 DBG (DBG_FNC, "> sane_get_select_fd\n");
2678
2679 /* silence gcc */
2680 handle = handle;
2681 fd = fd;
2682
2683 return SANE_STATUS_UNSUPPORTED;
2684 }
2685
2686 void
sane_close(SANE_Handle h)2687 sane_close (SANE_Handle h)
2688 {
2689 TScanner *scanner = (TScanner *) h;
2690
2691 DBG (DBG_FNC, "- sane_close...\n");
2692
2693 /* stop previous scans */
2694 RTS_Scanner_StopScan (device, TRUE);
2695
2696 /* close usb */
2697 sanei_usb_close (device->usb_handle);
2698
2699 /* free scanner internal variables */
2700 RTS_Scanner_End (device);
2701
2702 /* free RTS environment */
2703 RTS_Free (device);
2704
2705 /* free backend variables */
2706 if (scanner != NULL)
2707 {
2708 options_free (scanner);
2709
2710 img_buffers_free (scanner);
2711 }
2712 }
2713
2714 void
sane_exit(void)2715 sane_exit (void)
2716 {
2717 /* free device list memory */
2718 if (_pSaneDevList)
2719 {
2720 TDevListEntry *pDev, *pNext;
2721
2722 for (pDev = _pFirstSaneDev; pDev; pDev = pNext)
2723 {
2724 pNext = pDev->pNext;
2725 /* pDev->dev.name is the same pointer that pDev->devname */
2726 free (pDev->devname);
2727 free (pDev);
2728 }
2729
2730 _pFirstSaneDev = NULL;
2731 free (_pSaneDevList);
2732 _pSaneDevList = NULL;
2733 }
2734 }
2735