1 /* sane - Scanner Access Now Easy.
2 (C) Marian Matthias Eichholz 2001
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 as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19 As a special exception, the authors of SANE give permission for
20 additional uses of the libraries contained in this release of SANE.
21
22 The exception is that, if you link a SANE library with other files
23 to produce an executable, this does not by itself cause the
24 resulting executable to be covered by the GNU General Public
25 License. Your use of that executable is in no way restricted on
26 account of linking the SANE library code into it.
27
28 This exception does not, however, invalidate any other reasons why
29 the executable file might be covered by the GNU General Public
30 License.
31
32 If you submit changes to SANE to the maintainers to be included in
33 a subsequent release, you agree by submitting the changes that
34 those changes may be distributed with this exception intact.
35
36 If you write modifications of your own for SANE, it is your choice
37 whether to permit this exception to apply to your modifications.
38 If you do not wish that, delete this exception notice.
39
40 This file implements SANE backend for Microtek scanners with M011 USB
41 chip like the Microtek ScanMaker 3600, 3700 and 3750. */
42
43
44 /* ======================================================================
45
46 sm3600.c
47
48 SANE backend master module
49
50 (C) Marian Matthias Eichholz 2001
51
52 Start: 2.4.2001
53
54 ====================================================================== */
55
56 #include "../include/sane/config.h"
57 #include <stdlib.h>
58 #include <string.h>
59 #include <errno.h>
60
61 #define BUILD 6
62
63 #ifndef BACKEND_NAME
64 #define BACKEND_NAME sm3600
65 #endif
66
67 #include "../include/sane/sane.h"
68 #include "../include/sane/sanei.h"
69 #include "../include/sane/sanei_backend.h"
70 #include "../include/sane/sanei_config.h"
71 #include "../include/sane/saneopts.h"
72 #include "../include/sane/sanei_usb.h"
73
74 #undef HAVE_LIBUSB_LEGACY
75
76 /* prevent inclusion of scantool.h */
77 #define SCANTOOL_H
78 /* make no real function export, since we include the modules */
79 #define __SM3600EXPORT__ static
80
81 /* if defined, *before* sm3600.h inclusion */
82 #define SM3600_SUPPORT_EXPOSURE
83
84 #include "sm3600.h"
85
86 static unsigned long ulDebugMask;
87
88 static int num_devices;
89 static TDevice *pdevFirst;
90 static TInstance *pinstFirst;
91
92 /* ====================================================================== */
93
94 #include "sm3600-scanutil.c"
95 #include "sm3600-scanusb.c"
96 #include "sm3600-scanmtek.c"
97 #include "sm3600-homerun.c"
98 #include "sm3600-gray.c"
99 #include "sm3600-color.c"
100
101 /* ======================================================================
102
103 Initialise SANE options
104
105 ====================================================================== */
106
107 typedef enum { optCount,
108 optGroupMode, optMode, optResolution,
109 #ifdef SM3600_SUPPORT_EXPOSURE
110 optBrightness, optContrast,
111 #endif
112 optPreview, optGrayPreview,
113 optGroupGeometry,optTLX, optTLY, optBRX, optBRY,
114 optGroupEnhancement,
115 optGammaY, optGammaR,optGammaG,optGammaB,
116 optLast } TOptionIndex;
117
118 static const SANE_String_Const aScanModes[]= { "color", "gray", "lineart",
119 "halftone", NULL };
120
121 static const SANE_Range rangeXmm = {
122 SANE_FIX(0),
123 SANE_FIX(220),
124 SANE_FIX(0.1) };
125
126 static const SANE_Range rangeYmm = {
127 SANE_FIX(0),
128 SANE_FIX(300),
129 SANE_FIX(0.1) };
130
131 #ifdef SM3600_SUPPORT_EXPOSURE
132 static const SANE_Range rangeLumi = {
133 SANE_FIX(-100.0),
134 SANE_FIX(100.0),
135 SANE_FIX(1.0) };
136 #endif
137
138 static const SANE_Range rangeGamma = { 0, 4095, 1 };
139
140 static const SANE_Int setResolutions[] = { 5, 75,100,200,300,600 };
141
142 static
143 SANE_Status
InitOptions(TInstance *this)144 InitOptions(TInstance *this)
145 {
146 TOptionIndex iOpt;
147 if (optLast!=NUM_OPTIONS)
148 {
149 DBG(1,"NUM_OPTIONS does not fit!");
150 return SANE_STATUS_INVAL;
151 }
152 memset(this->aoptDesc,0,sizeof(this->aoptDesc));
153 memset(this->aoptVal,0,sizeof(this->aoptVal));
154 InitGammaTables(this,0,0);
155 for (iOpt=optCount; iOpt!=optLast; iOpt++)
156 {
157 static char *achNamesXY[]= {
158 SANE_NAME_SCAN_TL_X, SANE_NAME_SCAN_TL_Y,
159 SANE_NAME_SCAN_BR_X, SANE_NAME_SCAN_BR_Y };
160 static char *achTitlesXY[]= {
161 SANE_TITLE_SCAN_TL_X, SANE_TITLE_SCAN_TL_Y,
162 SANE_TITLE_SCAN_BR_X, SANE_TITLE_SCAN_BR_Y };
163 static char *achDescXY[]= {
164 SANE_DESC_SCAN_TL_X, SANE_DESC_SCAN_TL_Y,
165 SANE_DESC_SCAN_BR_X, SANE_DESC_SCAN_BR_Y };
166 static double afFullBed[] = { 22.0,30.0, 50.0, 80.0 }; /* TODO: calculate exactly! */
167 static const SANE_Range *aRangesXY[] = { &rangeXmm,&rangeYmm,&rangeXmm,&rangeYmm };
168 SANE_Option_Descriptor *pdesc;
169 Option_Value *pval;
170 /* shorthands */
171 pdesc=this->aoptDesc+iOpt;
172 pval=this->aoptVal+iOpt;
173 /* default */
174 pdesc->size=sizeof(SANE_Word);
175 pdesc->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
176
177 /*
178 Some hints:
179 *every* field needs a constraint, elseway there will be a warning.
180 */
181
182 switch (iOpt)
183 {
184 case optCount:
185 pdesc->title =SANE_TITLE_NUM_OPTIONS;
186 pdesc->desc =SANE_DESC_NUM_OPTIONS;
187 pdesc->type =SANE_TYPE_INT;
188 pdesc->cap =SANE_CAP_SOFT_DETECT;
189 pval->w =(SANE_Word)optLast;
190 break;
191 case optGroupMode:
192 pdesc->title="Mode";
193 pdesc->desc ="";
194 pdesc->type = SANE_TYPE_GROUP;
195 pdesc->cap = SANE_CAP_ADVANCED;
196 break;
197 case optMode:
198 pdesc->name =SANE_NAME_SCAN_MODE;
199 pdesc->title =SANE_TITLE_SCAN_MODE;
200 pdesc->desc ="Select the scan mode";
201 pdesc->type =SANE_TYPE_STRING;
202 pdesc->size =20;
203 pdesc->constraint_type = SANE_CONSTRAINT_STRING_LIST;
204 pdesc->constraint.string_list = aScanModes;
205 pval->s = strdup(aScanModes[color]);
206 break;
207 case optResolution:
208 pdesc->name =SANE_NAME_SCAN_RESOLUTION;
209 pdesc->title =SANE_TITLE_SCAN_RESOLUTION;
210 pdesc->desc =SANE_DESC_SCAN_RESOLUTION;
211 pdesc->type =SANE_TYPE_INT;
212 pdesc->unit =SANE_UNIT_DPI;
213 pdesc->constraint_type = SANE_CONSTRAINT_WORD_LIST;
214 pdesc->constraint.word_list = setResolutions;
215 pval->w =75;
216 break;
217 #ifdef SM3600_SUPPORT_EXPOSURE
218 case optBrightness:
219 pdesc->name =SANE_NAME_BRIGHTNESS;
220 pdesc->title =SANE_TITLE_BRIGHTNESS;
221 pdesc->desc =SANE_DESC_BRIGHTNESS;
222 pdesc->type =SANE_TYPE_FIXED;
223 pdesc->unit =SANE_UNIT_PERCENT;
224 pdesc->constraint_type =SANE_CONSTRAINT_RANGE;
225 pdesc->constraint.range=&rangeLumi;
226 pval->w =SANE_FIX(0);
227 break;
228 case optContrast:
229 pdesc->name =SANE_NAME_CONTRAST;
230 pdesc->title =SANE_TITLE_CONTRAST;
231 pdesc->desc =SANE_DESC_CONTRAST;
232 pdesc->type =SANE_TYPE_FIXED;
233 pdesc->unit =SANE_UNIT_PERCENT;
234 pdesc->constraint_type =SANE_CONSTRAINT_RANGE;
235 pdesc->constraint.range=&rangeLumi;
236 pval->w =SANE_FIX(0);
237 break;
238 #endif
239 case optPreview:
240 pdesc->name =SANE_NAME_PREVIEW;
241 pdesc->title =SANE_TITLE_PREVIEW;
242 pdesc->desc =SANE_DESC_PREVIEW;
243 pdesc->type =SANE_TYPE_BOOL;
244 pval->w =SANE_FALSE;
245 break;
246 case optGrayPreview:
247 pdesc->name =SANE_NAME_GRAY_PREVIEW;
248 pdesc->title =SANE_TITLE_GRAY_PREVIEW;
249 pdesc->desc =SANE_DESC_GRAY_PREVIEW;
250 pdesc->type =SANE_TYPE_BOOL;
251 pval->w =SANE_FALSE;
252 break;
253 case optGroupGeometry:
254 pdesc->title="Geometry";
255 pdesc->desc ="";
256 pdesc->type = SANE_TYPE_GROUP;
257 pdesc->constraint_type=SANE_CONSTRAINT_NONE;
258 pdesc->cap = SANE_CAP_ADVANCED;
259 break;
260 case optTLX: case optTLY: case optBRX: case optBRY:
261 pdesc->name =achNamesXY[iOpt-optTLX];
262 pdesc->title =achTitlesXY[iOpt-optTLX];
263 pdesc->desc =achDescXY[iOpt-optTLX];
264 pdesc->type =SANE_TYPE_FIXED;
265 pdesc->unit =SANE_UNIT_MM; /* arghh */
266 pdesc->constraint_type =SANE_CONSTRAINT_RANGE;
267 pdesc->constraint.range=aRangesXY[iOpt-optTLX];
268 pval->w =SANE_FIX(afFullBed[iOpt-optTLX]);
269 break;
270 case optGroupEnhancement:
271 pdesc->title="Enhancement";
272 pdesc->desc ="";
273 pdesc->type = SANE_TYPE_GROUP;
274 pdesc->constraint_type=SANE_CONSTRAINT_NONE;
275 pdesc->cap = SANE_CAP_ADVANCED;
276 break;
277 case optGammaY:
278 pdesc->name = SANE_NAME_GAMMA_VECTOR;
279 pdesc->title = SANE_TITLE_GAMMA_VECTOR;
280 pdesc->desc = SANE_DESC_GAMMA_VECTOR;
281 pdesc->type = SANE_TYPE_INT;
282 pdesc->unit = SANE_UNIT_NONE;
283 pdesc->size = 4096*sizeof(SANE_Int);
284 pdesc->constraint_type = SANE_CONSTRAINT_RANGE;
285 pdesc->constraint.range = &rangeGamma;
286 pval->wa = this->agammaY;
287 break;
288 case optGammaR:
289 pdesc->name = SANE_NAME_GAMMA_VECTOR_R;
290 pdesc->title = SANE_TITLE_GAMMA_VECTOR_R;
291 pdesc->desc = SANE_DESC_GAMMA_VECTOR_R;
292 pdesc->type = SANE_TYPE_INT;
293 pdesc->unit = SANE_UNIT_NONE;
294 pdesc->size = 4096*sizeof(SANE_Int);
295 pdesc->constraint_type = SANE_CONSTRAINT_RANGE;
296 pdesc->constraint.range = &rangeGamma;
297 pval->wa = this->agammaR;
298 break;
299 case optGammaG:
300 pdesc->name = SANE_NAME_GAMMA_VECTOR_G;
301 pdesc->title = SANE_TITLE_GAMMA_VECTOR_G;
302 pdesc->desc = SANE_DESC_GAMMA_VECTOR_G;
303 pdesc->type = SANE_TYPE_INT;
304 pdesc->unit = SANE_UNIT_NONE;
305 pdesc->size = 4096*sizeof(SANE_Int);
306 pdesc->constraint_type = SANE_CONSTRAINT_RANGE;
307 pdesc->constraint.range = &rangeGamma;
308 pval->wa = this->agammaG;
309 break;
310 case optGammaB:
311 pdesc->name = SANE_NAME_GAMMA_VECTOR_B;
312 pdesc->title = SANE_TITLE_GAMMA_VECTOR_B;
313 pdesc->desc = SANE_DESC_GAMMA_VECTOR_B;
314 pdesc->type = SANE_TYPE_INT;
315 pdesc->unit = SANE_UNIT_NONE;
316 pdesc->size = 4096*sizeof(SANE_Int);
317 pdesc->constraint_type = SANE_CONSTRAINT_RANGE;
318 pdesc->constraint.range = &rangeGamma;
319 pval->wa = this->agammaB;
320 break;
321 case optLast: /* not reached */
322 break;
323 }
324 }
325 return SANE_STATUS_GOOD;
326 }
327
328 static SANE_Status
RegisterSaneDev(TModel model, SANE_String_Const szName)329 RegisterSaneDev (TModel model, SANE_String_Const szName)
330 {
331 TDevice * q;
332
333 errno = 0;
334
335 q = malloc (sizeof (*q));
336 if (!q)
337 return SANE_STATUS_NO_MEM;
338
339 memset (q, 0, sizeof (*q)); /* clear every field */
340 q->szSaneName = strdup (szName);
341 q->sane.name = (SANE_String_Const) q->szSaneName;
342 q->sane.vendor = "Microtek";
343 q->sane.model = "ScanMaker 3600";
344 q->sane.type = "flatbed scanner";
345
346 q->model=model;
347
348 ++num_devices;
349 q->pNext = pdevFirst; /* link backwards */
350 pdevFirst = q;
351
352 return SANE_STATUS_GOOD;
353 }
354
355 static SANE_Status
sm_usb_attach(SANE_String_Const dev_name)356 sm_usb_attach (SANE_String_Const dev_name)
357 {
358 int fd;
359 SANE_Status err;
360 SANE_Word v, p;
361 TModel model;
362
363 err = sanei_usb_open(dev_name, &fd);
364 if (err)
365 return err;
366 err = sanei_usb_get_vendor_product (fd, &v, &p);
367 if (err)
368 {
369 sanei_usb_close (fd);
370 return err;
371 }
372 DBG (DEBUG_JUNK, "found dev %04X/%04X, %s\n", v, p, dev_name);
373 model = GetScannerModel (v, p);
374 if (model != unknown)
375 RegisterSaneDev (model, dev_name);
376
377 sanei_usb_close(fd);
378 return SANE_STATUS_GOOD;
379 }
380
381 SANE_Status
sane_init(SANE_Int *version_code, SANE_Auth_Callback authCB)382 sane_init (SANE_Int *version_code, SANE_Auth_Callback authCB)
383 {
384 int i;
385
386 DBG_INIT();
387
388 (void) authCB; /* compiler */
389
390 DBG(DEBUG_VERBOSE,"SM3600 init\n");
391 if (version_code)
392 {
393 *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
394 DBG(DEBUG_VERBOSE,"SM3600 version: %x\n",
395 SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD));
396 }
397
398 pdevFirst=NULL;
399
400 sanei_usb_init();
401 for (i = 0; aScanners[i].idProduct; i++)
402 {
403 sanei_usb_find_devices(SCANNER_VENDOR, aScanners[i].idProduct, sm_usb_attach);
404 }
405 return SANE_STATUS_GOOD;
406 }
407
408 static const SANE_Device ** devlist = 0; /* only pseudo-statical */
409
410 void
sane_exit(void)411 sane_exit (void)
412 {
413 TDevice *dev, *pNext;
414
415 /* free all bound resources and instances */
416 while (pinstFirst)
417 sane_close((SANE_Handle)pinstFirst); /* free all resources */
418
419 /* free all device descriptors */
420 for (dev = pdevFirst; dev; dev = pNext)
421 {
422 pNext = dev->pNext;
423 free (dev->szSaneName);
424 free (dev);
425 }
426 if (devlist) free(devlist);
427 devlist=NULL;
428 }
429
430 SANE_Status
sane_get_devices(const SANE_Device *** device_list, SANE_Bool __sane_unused__ local_only)431 sane_get_devices (const SANE_Device *** device_list,
432 SANE_Bool __sane_unused__ local_only)
433 {
434 TDevice *dev;
435 int i;
436
437 if (devlist) free (devlist);
438
439 devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
440 if (!devlist)
441 return SANE_STATUS_NO_MEM;
442
443 i = 0;
444 for (dev = pdevFirst; i < num_devices; dev = dev->pNext)
445 devlist[i++] = &dev->sane;
446 devlist[i++] = 0;
447
448 *device_list = devlist;
449 return SANE_STATUS_GOOD;
450 }
451
452 SANE_Status
sane_open(SANE_String_Const devicename, SANE_Handle *handle)453 sane_open (SANE_String_Const devicename, SANE_Handle *handle)
454 {
455 TDevice *pdev;
456 TInstance *this;
457 DBG(DEBUG_VERBOSE,"opening %s\n",devicename);
458 if (devicename[0]) /* selected */
459 {
460 for (pdev=pdevFirst; pdev; pdev=pdev->pNext)
461 {
462 DBG(DEBUG_VERBOSE,"%s<>%s\n",devicename, pdev->sane.name);
463 if (!strcmp(devicename,pdev->sane.name))
464 break;
465 }
466 /* no dynamic post-registration */
467 }
468 else
469 pdev=pdevFirst;
470 if (!pdev)
471 return SANE_STATUS_INVAL;
472 this = (TInstance*) calloc(1,sizeof(TInstance));
473 if (!this) return SANE_STATUS_NO_MEM;
474
475 *handle = (SANE_Handle)this;
476
477 ResetCalibration(this); /* do not release memory */
478 this->pNext=pinstFirst; /* register open handle */
479 pinstFirst=this;
480 this->model=pdev->model; /* memorize model */
481 /* open and prepare USB scanner handle */
482
483 if (sanei_usb_open (devicename, &this->hScanner) != SANE_STATUS_GOOD)
484 return SetError (this, SANE_STATUS_IO_ERROR, "cannot open scanner device");
485
486 this->quality=fast;
487 return InitOptions(this);
488 }
489
490 void
sane_close(SANE_Handle handle)491 sane_close (SANE_Handle handle)
492 {
493 TInstance *this,*pParent,*p;
494 this=(TInstance*)handle;
495 DBG(DEBUG_VERBOSE,"closing scanner\n");
496 if (this->hScanner)
497 {
498 if (this->state.bScanning)
499 EndScan(this);
500
501 sanei_usb_close(this->hScanner);
502 this->hScanner=-1;
503 }
504 ResetCalibration(this); /* release calibration data */
505 /* unlink active device entry */
506 pParent=NULL;
507 for (p=pinstFirst; p; p=p->pNext)
508 {
509 if (p==this) break;
510 pParent=p;
511 }
512
513 if (!p)
514 {
515 DBG(1,"invalid handle in close()\n");
516 return;
517 }
518 /* delete instance from instance list */
519 if (pParent)
520 pParent->pNext=this->pNext;
521 else
522 pinstFirst=this->pNext; /* NULL with last entry */
523 /* free resources */
524 if (this->pchPageBuffer)
525 free(this->pchPageBuffer);
526 if (this->szErrorReason)
527 {
528 DBG(DEBUG_VERBOSE,"Error status: %d, %s",
529 this->nErrorState, this->szErrorReason);
530 free(this->szErrorReason);
531 }
532 free(this);
533 }
534
535 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle, SANE_Int iOpt)536 sane_get_option_descriptor (SANE_Handle handle, SANE_Int iOpt)
537 {
538 TInstance *this=(TInstance*)handle;
539 if (iOpt<NUM_OPTIONS)
540 return this->aoptDesc+iOpt;
541 return NULL;
542 }
543
544 SANE_Status
sane_control_option(SANE_Handle handle, SANE_Int iOpt, SANE_Action action, void *pVal, SANE_Int *pnInfo)545 sane_control_option (SANE_Handle handle, SANE_Int iOpt,
546 SANE_Action action, void *pVal,
547 SANE_Int *pnInfo)
548 {
549 SANE_Word cap;
550 SANE_Status rc;
551 TInstance *this;
552 this=(TInstance*)handle;
553 rc=SANE_STATUS_GOOD;
554 if (pnInfo)
555 *pnInfo=0;
556
557 if (this->state.bScanning)
558 return SANE_STATUS_DEVICE_BUSY;
559 if (iOpt>=NUM_OPTIONS)
560 return SANE_STATUS_INVAL;
561
562 cap=this->aoptDesc[iOpt].cap;
563
564 switch (action)
565 {
566
567 /* ------------------------------------------------------------ */
568
569 case SANE_ACTION_GET_VALUE:
570 switch ((TOptionIndex)iOpt)
571 {
572 case optCount:
573 case optPreview:
574 case optGrayPreview:
575 case optResolution:
576 #ifdef SM3600_SUPPORT_EXPOSURE
577 case optBrightness:
578 case optContrast:
579 #endif
580 case optTLX: case optTLY: case optBRX: case optBRY:
581 *(SANE_Word*)pVal = this->aoptVal[iOpt].w;
582 break;
583 case optMode:
584 strcpy(pVal,this->aoptVal[iOpt].s);
585 break;
586 case optGammaY:
587 case optGammaR:
588 case optGammaG:
589 case optGammaB:
590 DBG(DEBUG_INFO,"getting gamma\n");
591 memcpy(pVal,this->aoptVal[iOpt].wa, this->aoptDesc[iOpt].size);
592 break;
593 default:
594 return SANE_STATUS_INVAL;
595 }
596 break;
597
598 /* ------------------------------------------------------------ */
599
600 case SANE_ACTION_SET_VALUE:
601 if (!SANE_OPTION_IS_SETTABLE(cap))
602 return SANE_STATUS_INVAL;
603 rc=sanei_constrain_value(this->aoptDesc+iOpt,pVal,pnInfo);
604 if (rc!=SANE_STATUS_GOOD)
605 return rc;
606 switch ((TOptionIndex)iOpt)
607 {
608 case optResolution:
609 case optTLX: case optTLY: case optBRX: case optBRY:
610 if (pnInfo) (*pnInfo) |= SANE_INFO_RELOAD_PARAMS;
611 // fall through
612 case optPreview:
613 case optGrayPreview:
614 #ifdef SM3600_SUPPORT_EXPOSURE
615 case optBrightness:
616 case optContrast:
617 #endif
618 this->aoptVal[iOpt].w = *(SANE_Word*)pVal;
619 break;
620 case optMode:
621 if (pnInfo)
622 (*pnInfo) |= SANE_INFO_RELOAD_PARAMS
623 | SANE_INFO_RELOAD_OPTIONS;
624 strcpy(this->aoptVal[iOpt].s,pVal);
625 break;
626 case optGammaY:
627 case optGammaR: case optGammaG: case optGammaB:
628 DBG(DEBUG_INFO,"setting gamma #%d\n",iOpt);
629 memcpy(this->aoptVal[iOpt].wa, pVal, this->aoptDesc[iOpt].size);
630 break;
631 default:
632 return SANE_STATUS_INVAL;
633 }
634 break;
635 case SANE_ACTION_SET_AUTO:
636 return SANE_STATUS_UNSUPPORTED;
637 } /* switch action */
638 return rc; /* normally GOOD */
639 }
640
641 static SANE_Status
SetupInternalParameters(TInstance *this)642 SetupInternalParameters(TInstance *this)
643 {
644 int i;
645 this->param.res=(int)this->aoptVal[optResolution].w;
646 #ifdef SM3600_SUPPORT_EXPOSURE
647 this->param.nBrightness=(int)(this->aoptVal[optBrightness].w>>SANE_FIXED_SCALE_SHIFT);
648 this->param.nContrast=(int)(this->aoptVal[optContrast].w>>SANE_FIXED_SCALE_SHIFT);
649 #else
650 this->param.nBrightness=0;
651 this->param.nContrast=0;
652 #endif
653 this->param.x=(int)(SANE_UNFIX(this->aoptVal[optTLX].w)*1200.0/25.4);
654 this->param.y=(int)(SANE_UNFIX(this->aoptVal[optTLY].w)*1200.0/25.4);
655 this->param.cx=(int)(SANE_UNFIX(this->aoptVal[optBRX].w-this->aoptVal[optTLX].w)*1200.0/25.4)+1;
656 this->param.cy=(int)(SANE_UNFIX(this->aoptVal[optBRY].w-this->aoptVal[optTLY].w)*1200.0/25.4)+1;
657 for (i=0; aScanModes[i]; i++)
658 if (!strcasecmp(this->aoptVal[optMode].s,aScanModes[i]))
659 {
660 this->mode=(TMode)i;
661 break;
662 }
663 DBG(DEBUG_INFO,"mode=%d, res=%d, BC=[%d,%d], xywh=[%d,%d,%d,%d]\n",
664 this->mode, this->param.res,
665 this->param.nBrightness, this->param.nContrast,
666 this->param.x,this->param.y,this->param.cx,this->param.cy);
667 return SANE_STATUS_GOOD;
668 }
669
670 SANE_Status
sane_get_parameters(SANE_Handle handle, SANE_Parameters *p)671 sane_get_parameters (SANE_Handle handle, SANE_Parameters *p)
672 {
673 /* extremely important for xscanimage */
674 TInstance *this;
675 this=(TInstance*)handle;
676 SetupInternalParameters(this);
677 GetAreaSize(this);
678 p->pixels_per_line=this->state.cxPixel;
679 /* TODO: we need a more stable cyPixel prediction */
680 p->lines=this->state.cyPixel;
681 p->last_frame=SANE_TRUE;
682 switch (this->mode)
683 {
684 case color:
685 p->format=SANE_FRAME_RGB;
686 p->depth=8;
687 p->bytes_per_line=p->pixels_per_line*3;
688 break;
689 case gray:
690 p->format=SANE_FRAME_GRAY;
691 p->depth=8;
692 p->bytes_per_line=p->pixels_per_line;
693 break;
694 case halftone:
695 case line:
696 p->format=SANE_FRAME_GRAY;
697 p->depth=1;
698 p->bytes_per_line=(p->pixels_per_line+7)/8;
699 break;
700 }
701 DBG(DEBUG_INFO,"getting parameters (%d,%d)...\n",p->bytes_per_line,p->lines);
702 return SANE_STATUS_GOOD;
703 }
704
705 SANE_Status
sane_start(SANE_Handle handle)706 sane_start (SANE_Handle handle)
707 {
708 TInstance *this;
709 SANE_Status rc;
710 this=(TInstance*)handle;
711 DBG(DEBUG_VERBOSE,"starting scan...\n");
712 if (this->state.bScanning) return SANE_STATUS_DEVICE_BUSY;
713 rc=SetupInternalParameters(this);
714 this->state.bCanceled=false;
715 if (!rc) rc=DoInit(this); /* oopsi, we should initialise :-) */
716 if (!rc && !this->bOptSkipOriginate) rc=DoOriginate(this,true);
717 if (!rc) rc=DoJog(this,this->calibration.yMargin);
718 if (rc) return rc;
719 this->state.bEOF=false;
720 switch (this->mode)
721 {
722 case color: rc=StartScanColor(this); break;
723 default: rc=StartScanGray(this); break;
724 }
725 if (this->state.bCanceled) return SANE_STATUS_CANCELLED;
726 return rc;
727 }
728
729 SANE_Status
sane_read(SANE_Handle handle, SANE_Byte *puchBuffer, SANE_Int cchMax, SANE_Int *pcchRead)730 sane_read (SANE_Handle handle, SANE_Byte *puchBuffer,
731 SANE_Int cchMax,
732 SANE_Int *pcchRead)
733 {
734 SANE_Status rc;
735 TInstance *this;
736 this=(TInstance*)handle;
737 DBG(DEBUG_INFO,"reading chunk %d...\n",(int)cchMax);
738 *pcchRead=0;
739 if (this->state.bEOF)
740 return SANE_STATUS_EOF;
741 rc=ReadChunk(this,puchBuffer,cchMax,pcchRead);
742 DBG(DEBUG_INFO,"... line %d (%d/%d)...\n",this->state.iLine,*pcchRead,rc);
743 switch (rc)
744 {
745 case SANE_STATUS_EOF:
746 this->state.bEOF=true; /* flag EOF on next read() */
747 rc=SANE_STATUS_GOOD; /* we do not flag THIS block! */
748 break;
749 case SANE_STATUS_GOOD:
750 if (!*pcchRead) rc=SANE_STATUS_EOF;
751 break;
752 default:
753 break;
754 }
755 return rc;
756 }
757
758 void
sane_cancel(SANE_Handle handle)759 sane_cancel (SANE_Handle handle)
760 {
761 TInstance *this;
762 this=(TInstance*)handle;
763 DBG(DEBUG_VERBOSE,"cancel called...\n");
764 if (this->state.bScanning)
765 {
766 this->state.bCanceled=true;
767 if (this->state.bEOF) /* regular (fast) cancel */
768 {
769 DBG(DEBUG_INFO,"regular end cancel\n");
770 EndScan(this);
771 DoJog(this,-this->calibration.yMargin);
772 }
773 else
774 {
775 /* since Xsane does not continue scanning,
776 we cannot defer cancellation */
777 DBG(DEBUG_INFO,"hard cancel called...\n");
778 CancelScan(this);
779 }
780 }
781 }
782
783 SANE_Status
sane_set_io_mode(SANE_Handle h, SANE_Bool m)784 sane_set_io_mode(SANE_Handle h, SANE_Bool m)
785 {
786 (void) h;
787 if (m==SANE_TRUE) /* no non-blocking-mode */
788 return SANE_STATUS_UNSUPPORTED;
789 return SANE_STATUS_GOOD;
790 }
791
792 SANE_Status
sane_get_select_fd(SANE_Handle handle, SANE_Int *fd)793 sane_get_select_fd(SANE_Handle handle, SANE_Int *fd)
794 {
795 (void) handle; (void) fd;
796 return SANE_STATUS_UNSUPPORTED; /* we have no file IO */
797 }
798