1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci   (C) Marian Matthias Eichholz 2001
3141cc406Sopenharmony_ci
4141cc406Sopenharmony_ci   This file is part of the SANE package.
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
7141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
8141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
9141cc406Sopenharmony_ci   License, or (at your option) any later version.
10141cc406Sopenharmony_ci
11141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
12141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
13141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14141cc406Sopenharmony_ci   General Public License for more details.
15141cc406Sopenharmony_ci
16141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
17141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
18141cc406Sopenharmony_ci
19141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
20141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
23141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
24141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
25141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
26141cc406Sopenharmony_ci   account of linking the SANE library code into it.
27141cc406Sopenharmony_ci
28141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
29141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
30141cc406Sopenharmony_ci   License.
31141cc406Sopenharmony_ci
32141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
33141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
34141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
35141cc406Sopenharmony_ci
36141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
37141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
38141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
39141cc406Sopenharmony_ci
40141cc406Sopenharmony_ci   This file implements SANE backend for Microtek scanners with M011 USB
41141cc406Sopenharmony_ci   chip like the Microtek ScanMaker 3600, 3700 and 3750. */
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci/* ======================================================================
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_cism3600.c
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ciSANE backend master module
49141cc406Sopenharmony_ci
50141cc406Sopenharmony_ci(C) Marian Matthias Eichholz 2001
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ciStart: 2.4.2001
53141cc406Sopenharmony_ci
54141cc406Sopenharmony_ci====================================================================== */
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci#include "../include/sane/config.h"
57141cc406Sopenharmony_ci#include <stdlib.h>
58141cc406Sopenharmony_ci#include <string.h>
59141cc406Sopenharmony_ci#include <errno.h>
60141cc406Sopenharmony_ci
61141cc406Sopenharmony_ci#define BUILD	6
62141cc406Sopenharmony_ci
63141cc406Sopenharmony_ci#ifndef BACKEND_NAME
64141cc406Sopenharmony_ci#define BACKEND_NAME sm3600
65141cc406Sopenharmony_ci#endif
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_ci#include "../include/sane/sane.h"
68141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
69141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
70141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
71141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
72141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
73141cc406Sopenharmony_ci
74141cc406Sopenharmony_ci#undef HAVE_LIBUSB_LEGACY
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_ci/* prevent inclusion of scantool.h */
77141cc406Sopenharmony_ci#define SCANTOOL_H
78141cc406Sopenharmony_ci/* make no real function export, since we include the modules */
79141cc406Sopenharmony_ci#define __SM3600EXPORT__ static
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_ci/* if defined, *before* sm3600.h inclusion */
82141cc406Sopenharmony_ci#define SM3600_SUPPORT_EXPOSURE
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_ci#include "sm3600.h"
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_cistatic unsigned long ulDebugMask;
87141cc406Sopenharmony_ci
88141cc406Sopenharmony_cistatic int		num_devices;
89141cc406Sopenharmony_cistatic TDevice        *pdevFirst;
90141cc406Sopenharmony_cistatic TInstance      *pinstFirst;
91141cc406Sopenharmony_ci
92141cc406Sopenharmony_ci/* ====================================================================== */
93141cc406Sopenharmony_ci
94141cc406Sopenharmony_ci#include "sm3600-scanutil.c"
95141cc406Sopenharmony_ci#include "sm3600-scanusb.c"
96141cc406Sopenharmony_ci#include "sm3600-scanmtek.c"
97141cc406Sopenharmony_ci#include "sm3600-homerun.c"
98141cc406Sopenharmony_ci#include "sm3600-gray.c"
99141cc406Sopenharmony_ci#include "sm3600-color.c"
100141cc406Sopenharmony_ci
101141cc406Sopenharmony_ci/* ======================================================================
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ciInitialise SANE options
104141cc406Sopenharmony_ci
105141cc406Sopenharmony_ci====================================================================== */
106141cc406Sopenharmony_ci
107141cc406Sopenharmony_citypedef enum { optCount,
108141cc406Sopenharmony_ci	       optGroupMode, optMode, optResolution,
109141cc406Sopenharmony_ci#ifdef SM3600_SUPPORT_EXPOSURE
110141cc406Sopenharmony_ci	       optBrightness, optContrast,
111141cc406Sopenharmony_ci#endif
112141cc406Sopenharmony_ci	       optPreview, optGrayPreview,
113141cc406Sopenharmony_ci	       optGroupGeometry,optTLX, optTLY, optBRX, optBRY,
114141cc406Sopenharmony_ci	       optGroupEnhancement,
115141cc406Sopenharmony_ci	       optGammaY, optGammaR,optGammaG,optGammaB,
116141cc406Sopenharmony_ci	       optLast } TOptionIndex;
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_cistatic const SANE_String_Const aScanModes[]= {  "color", "gray", "lineart",
119141cc406Sopenharmony_ci						"halftone", NULL };
120141cc406Sopenharmony_ci
121141cc406Sopenharmony_cistatic const SANE_Range rangeXmm = {
122141cc406Sopenharmony_ci  SANE_FIX(0),
123141cc406Sopenharmony_ci  SANE_FIX(220),
124141cc406Sopenharmony_ci  SANE_FIX(0.1) };
125141cc406Sopenharmony_ci
126141cc406Sopenharmony_cistatic const SANE_Range rangeYmm = {
127141cc406Sopenharmony_ci  SANE_FIX(0),
128141cc406Sopenharmony_ci  SANE_FIX(300),
129141cc406Sopenharmony_ci  SANE_FIX(0.1) };
130141cc406Sopenharmony_ci
131141cc406Sopenharmony_ci#ifdef SM3600_SUPPORT_EXPOSURE
132141cc406Sopenharmony_cistatic const SANE_Range rangeLumi = {
133141cc406Sopenharmony_ci  SANE_FIX(-100.0),
134141cc406Sopenharmony_ci  SANE_FIX(100.0),
135141cc406Sopenharmony_ci  SANE_FIX(1.0) };
136141cc406Sopenharmony_ci#endif
137141cc406Sopenharmony_ci
138141cc406Sopenharmony_cistatic const SANE_Range rangeGamma = { 0, 4095, 1 };
139141cc406Sopenharmony_ci
140141cc406Sopenharmony_cistatic const SANE_Int setResolutions[] = { 5, 75,100,200,300,600 };
141141cc406Sopenharmony_ci
142141cc406Sopenharmony_cistatic
143141cc406Sopenharmony_ciSANE_Status
144141cc406Sopenharmony_ciInitOptions(TInstance *this)
145141cc406Sopenharmony_ci{
146141cc406Sopenharmony_ci  TOptionIndex iOpt;
147141cc406Sopenharmony_ci  if (optLast!=NUM_OPTIONS)
148141cc406Sopenharmony_ci    {
149141cc406Sopenharmony_ci      DBG(1,"NUM_OPTIONS does not fit!");
150141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
151141cc406Sopenharmony_ci    }
152141cc406Sopenharmony_ci  memset(this->aoptDesc,0,sizeof(this->aoptDesc));
153141cc406Sopenharmony_ci  memset(this->aoptVal,0,sizeof(this->aoptVal));
154141cc406Sopenharmony_ci  InitGammaTables(this,0,0);
155141cc406Sopenharmony_ci  for (iOpt=optCount; iOpt!=optLast; iOpt++)
156141cc406Sopenharmony_ci    {
157141cc406Sopenharmony_ci      static char *achNamesXY[]= {
158141cc406Sopenharmony_ci	SANE_NAME_SCAN_TL_X,	SANE_NAME_SCAN_TL_Y,
159141cc406Sopenharmony_ci	SANE_NAME_SCAN_BR_X,	SANE_NAME_SCAN_BR_Y };
160141cc406Sopenharmony_ci      static char *achTitlesXY[]= {
161141cc406Sopenharmony_ci	SANE_TITLE_SCAN_TL_X,	SANE_TITLE_SCAN_TL_Y,
162141cc406Sopenharmony_ci	SANE_TITLE_SCAN_BR_X,	SANE_TITLE_SCAN_BR_Y };
163141cc406Sopenharmony_ci      static char *achDescXY[]= {
164141cc406Sopenharmony_ci	SANE_DESC_SCAN_TL_X,	SANE_DESC_SCAN_TL_Y,
165141cc406Sopenharmony_ci	SANE_DESC_SCAN_BR_X,	SANE_DESC_SCAN_BR_Y };
166141cc406Sopenharmony_ci      static double afFullBed[] = { 22.0,30.0, 50.0, 80.0 }; /* TODO: calculate exactly! */
167141cc406Sopenharmony_ci      static const SANE_Range *aRangesXY[] = { &rangeXmm,&rangeYmm,&rangeXmm,&rangeYmm };
168141cc406Sopenharmony_ci      SANE_Option_Descriptor *pdesc;
169141cc406Sopenharmony_ci      Option_Value           *pval;
170141cc406Sopenharmony_ci      /* shorthands */
171141cc406Sopenharmony_ci      pdesc=this->aoptDesc+iOpt;
172141cc406Sopenharmony_ci      pval=this->aoptVal+iOpt;
173141cc406Sopenharmony_ci      /* default */
174141cc406Sopenharmony_ci      pdesc->size=sizeof(SANE_Word);
175141cc406Sopenharmony_ci      pdesc->cap=SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
176141cc406Sopenharmony_ci
177141cc406Sopenharmony_ci      /*
178141cc406Sopenharmony_ci	Some hints:
179141cc406Sopenharmony_ci	*every* field needs a constraint, elseway there will be a warning.
180141cc406Sopenharmony_ci	*/
181141cc406Sopenharmony_ci
182141cc406Sopenharmony_ci      switch (iOpt)
183141cc406Sopenharmony_ci	{
184141cc406Sopenharmony_ci	case optCount:
185141cc406Sopenharmony_ci	  pdesc->title  =SANE_TITLE_NUM_OPTIONS;
186141cc406Sopenharmony_ci	  pdesc->desc   =SANE_DESC_NUM_OPTIONS;
187141cc406Sopenharmony_ci	  pdesc->type   =SANE_TYPE_INT;
188141cc406Sopenharmony_ci	  pdesc->cap    =SANE_CAP_SOFT_DETECT;
189141cc406Sopenharmony_ci	  pval->w       =(SANE_Word)optLast;
190141cc406Sopenharmony_ci	  break;
191141cc406Sopenharmony_ci	case optGroupMode:
192141cc406Sopenharmony_ci	  pdesc->title="Mode";
193141cc406Sopenharmony_ci	  pdesc->desc ="";
194141cc406Sopenharmony_ci	  pdesc->type = SANE_TYPE_GROUP;
195141cc406Sopenharmony_ci	  pdesc->cap  = SANE_CAP_ADVANCED;
196141cc406Sopenharmony_ci	  break;
197141cc406Sopenharmony_ci	case optMode:
198141cc406Sopenharmony_ci	  pdesc->name   =SANE_NAME_SCAN_MODE;
199141cc406Sopenharmony_ci	  pdesc->title  =SANE_TITLE_SCAN_MODE;
200141cc406Sopenharmony_ci	  pdesc->desc   ="Select the scan mode";
201141cc406Sopenharmony_ci	  pdesc->type   =SANE_TYPE_STRING;
202141cc406Sopenharmony_ci	  pdesc->size   =20;
203141cc406Sopenharmony_ci	  pdesc->constraint_type = SANE_CONSTRAINT_STRING_LIST;
204141cc406Sopenharmony_ci	  pdesc->constraint.string_list = aScanModes;
205141cc406Sopenharmony_ci	  pval->s       = strdup(aScanModes[color]);
206141cc406Sopenharmony_ci	  break;
207141cc406Sopenharmony_ci	case optResolution:
208141cc406Sopenharmony_ci	  pdesc->name   =SANE_NAME_SCAN_RESOLUTION;
209141cc406Sopenharmony_ci	  pdesc->title  =SANE_TITLE_SCAN_RESOLUTION;
210141cc406Sopenharmony_ci	  pdesc->desc   =SANE_DESC_SCAN_RESOLUTION;
211141cc406Sopenharmony_ci	  pdesc->type   =SANE_TYPE_INT;
212141cc406Sopenharmony_ci	  pdesc->unit   =SANE_UNIT_DPI;
213141cc406Sopenharmony_ci	  pdesc->constraint_type = SANE_CONSTRAINT_WORD_LIST;
214141cc406Sopenharmony_ci	  pdesc->constraint.word_list = setResolutions;
215141cc406Sopenharmony_ci	  pval->w       =75;
216141cc406Sopenharmony_ci	  break;
217141cc406Sopenharmony_ci#ifdef SM3600_SUPPORT_EXPOSURE
218141cc406Sopenharmony_ci	case optBrightness:
219141cc406Sopenharmony_ci	  pdesc->name   =SANE_NAME_BRIGHTNESS;
220141cc406Sopenharmony_ci	  pdesc->title  =SANE_TITLE_BRIGHTNESS;
221141cc406Sopenharmony_ci	  pdesc->desc   =SANE_DESC_BRIGHTNESS;
222141cc406Sopenharmony_ci	  pdesc->type   =SANE_TYPE_FIXED;
223141cc406Sopenharmony_ci	  pdesc->unit   =SANE_UNIT_PERCENT;
224141cc406Sopenharmony_ci	  pdesc->constraint_type =SANE_CONSTRAINT_RANGE;
225141cc406Sopenharmony_ci	  pdesc->constraint.range=&rangeLumi;
226141cc406Sopenharmony_ci	  pval->w       =SANE_FIX(0);
227141cc406Sopenharmony_ci	  break;
228141cc406Sopenharmony_ci	case optContrast:
229141cc406Sopenharmony_ci	  pdesc->name   =SANE_NAME_CONTRAST;
230141cc406Sopenharmony_ci	  pdesc->title  =SANE_TITLE_CONTRAST;
231141cc406Sopenharmony_ci	  pdesc->desc   =SANE_DESC_CONTRAST;
232141cc406Sopenharmony_ci	  pdesc->type   =SANE_TYPE_FIXED;
233141cc406Sopenharmony_ci	  pdesc->unit   =SANE_UNIT_PERCENT;
234141cc406Sopenharmony_ci	  pdesc->constraint_type =SANE_CONSTRAINT_RANGE;
235141cc406Sopenharmony_ci	  pdesc->constraint.range=&rangeLumi;
236141cc406Sopenharmony_ci	  pval->w       =SANE_FIX(0);
237141cc406Sopenharmony_ci	  break;
238141cc406Sopenharmony_ci#endif
239141cc406Sopenharmony_ci	case optPreview:
240141cc406Sopenharmony_ci	  pdesc->name   =SANE_NAME_PREVIEW;
241141cc406Sopenharmony_ci	  pdesc->title  =SANE_TITLE_PREVIEW;
242141cc406Sopenharmony_ci	  pdesc->desc   =SANE_DESC_PREVIEW;
243141cc406Sopenharmony_ci	  pdesc->type   =SANE_TYPE_BOOL;
244141cc406Sopenharmony_ci	  pval->w       =SANE_FALSE;
245141cc406Sopenharmony_ci	  break;
246141cc406Sopenharmony_ci	case optGrayPreview:
247141cc406Sopenharmony_ci	  pdesc->name   =SANE_NAME_GRAY_PREVIEW;
248141cc406Sopenharmony_ci	  pdesc->title  =SANE_TITLE_GRAY_PREVIEW;
249141cc406Sopenharmony_ci	  pdesc->desc   =SANE_DESC_GRAY_PREVIEW;
250141cc406Sopenharmony_ci	  pdesc->type   =SANE_TYPE_BOOL;
251141cc406Sopenharmony_ci	  pval->w       =SANE_FALSE;
252141cc406Sopenharmony_ci	  break;
253141cc406Sopenharmony_ci	case optGroupGeometry:
254141cc406Sopenharmony_ci	  pdesc->title="Geometry";
255141cc406Sopenharmony_ci	  pdesc->desc ="";
256141cc406Sopenharmony_ci	  pdesc->type = SANE_TYPE_GROUP;
257141cc406Sopenharmony_ci	  pdesc->constraint_type=SANE_CONSTRAINT_NONE;
258141cc406Sopenharmony_ci	  pdesc->cap  = SANE_CAP_ADVANCED;
259141cc406Sopenharmony_ci	  break;
260141cc406Sopenharmony_ci	case optTLX: case optTLY: case optBRX: case optBRY:
261141cc406Sopenharmony_ci	  pdesc->name   =achNamesXY[iOpt-optTLX];
262141cc406Sopenharmony_ci	  pdesc->title  =achTitlesXY[iOpt-optTLX];
263141cc406Sopenharmony_ci	  pdesc->desc   =achDescXY[iOpt-optTLX];
264141cc406Sopenharmony_ci	  pdesc->type   =SANE_TYPE_FIXED;
265141cc406Sopenharmony_ci	  pdesc->unit   =SANE_UNIT_MM; /* arghh */
266141cc406Sopenharmony_ci	  pdesc->constraint_type =SANE_CONSTRAINT_RANGE;
267141cc406Sopenharmony_ci	  pdesc->constraint.range=aRangesXY[iOpt-optTLX];
268141cc406Sopenharmony_ci	  pval->w       =SANE_FIX(afFullBed[iOpt-optTLX]);
269141cc406Sopenharmony_ci	  break;
270141cc406Sopenharmony_ci	case optGroupEnhancement:
271141cc406Sopenharmony_ci	  pdesc->title="Enhancement";
272141cc406Sopenharmony_ci	  pdesc->desc ="";
273141cc406Sopenharmony_ci	  pdesc->type = SANE_TYPE_GROUP;
274141cc406Sopenharmony_ci	  pdesc->constraint_type=SANE_CONSTRAINT_NONE;
275141cc406Sopenharmony_ci	  pdesc->cap  = SANE_CAP_ADVANCED;
276141cc406Sopenharmony_ci	  break;
277141cc406Sopenharmony_ci	case optGammaY:
278141cc406Sopenharmony_ci	  pdesc->name     = SANE_NAME_GAMMA_VECTOR;
279141cc406Sopenharmony_ci	  pdesc->title    = SANE_TITLE_GAMMA_VECTOR;
280141cc406Sopenharmony_ci	  pdesc->desc     = SANE_DESC_GAMMA_VECTOR;
281141cc406Sopenharmony_ci	  pdesc->type     = SANE_TYPE_INT;
282141cc406Sopenharmony_ci	  pdesc->unit     = SANE_UNIT_NONE;
283141cc406Sopenharmony_ci	  pdesc->size     = 4096*sizeof(SANE_Int);
284141cc406Sopenharmony_ci	  pdesc->constraint_type = SANE_CONSTRAINT_RANGE;
285141cc406Sopenharmony_ci	  pdesc->constraint.range = &rangeGamma;
286141cc406Sopenharmony_ci	  pval->wa        = this->agammaY;
287141cc406Sopenharmony_ci	  break;
288141cc406Sopenharmony_ci	case optGammaR:
289141cc406Sopenharmony_ci	  pdesc->name     = SANE_NAME_GAMMA_VECTOR_R;
290141cc406Sopenharmony_ci	  pdesc->title    = SANE_TITLE_GAMMA_VECTOR_R;
291141cc406Sopenharmony_ci	  pdesc->desc     = SANE_DESC_GAMMA_VECTOR_R;
292141cc406Sopenharmony_ci	  pdesc->type     = SANE_TYPE_INT;
293141cc406Sopenharmony_ci	  pdesc->unit     = SANE_UNIT_NONE;
294141cc406Sopenharmony_ci	  pdesc->size     = 4096*sizeof(SANE_Int);
295141cc406Sopenharmony_ci	  pdesc->constraint_type = SANE_CONSTRAINT_RANGE;
296141cc406Sopenharmony_ci	  pdesc->constraint.range = &rangeGamma;
297141cc406Sopenharmony_ci	  pval->wa        = this->agammaR;
298141cc406Sopenharmony_ci	  break;
299141cc406Sopenharmony_ci	case optGammaG:
300141cc406Sopenharmony_ci	  pdesc->name     = SANE_NAME_GAMMA_VECTOR_G;
301141cc406Sopenharmony_ci	  pdesc->title    = SANE_TITLE_GAMMA_VECTOR_G;
302141cc406Sopenharmony_ci	  pdesc->desc     = SANE_DESC_GAMMA_VECTOR_G;
303141cc406Sopenharmony_ci	  pdesc->type     = SANE_TYPE_INT;
304141cc406Sopenharmony_ci	  pdesc->unit     = SANE_UNIT_NONE;
305141cc406Sopenharmony_ci	  pdesc->size     = 4096*sizeof(SANE_Int);
306141cc406Sopenharmony_ci	  pdesc->constraint_type = SANE_CONSTRAINT_RANGE;
307141cc406Sopenharmony_ci	  pdesc->constraint.range = &rangeGamma;
308141cc406Sopenharmony_ci	  pval->wa        = this->agammaG;
309141cc406Sopenharmony_ci	  break;
310141cc406Sopenharmony_ci	case optGammaB:
311141cc406Sopenharmony_ci	  pdesc->name     = SANE_NAME_GAMMA_VECTOR_B;
312141cc406Sopenharmony_ci	  pdesc->title    = SANE_TITLE_GAMMA_VECTOR_B;
313141cc406Sopenharmony_ci	  pdesc->desc     = SANE_DESC_GAMMA_VECTOR_B;
314141cc406Sopenharmony_ci	  pdesc->type     = SANE_TYPE_INT;
315141cc406Sopenharmony_ci	  pdesc->unit     = SANE_UNIT_NONE;
316141cc406Sopenharmony_ci	  pdesc->size     = 4096*sizeof(SANE_Int);
317141cc406Sopenharmony_ci	  pdesc->constraint_type = SANE_CONSTRAINT_RANGE;
318141cc406Sopenharmony_ci	  pdesc->constraint.range = &rangeGamma;
319141cc406Sopenharmony_ci	  pval->wa        = this->agammaB;
320141cc406Sopenharmony_ci	  break;
321141cc406Sopenharmony_ci	case optLast: /* not reached */
322141cc406Sopenharmony_ci	  break;
323141cc406Sopenharmony_ci	}
324141cc406Sopenharmony_ci    }
325141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
326141cc406Sopenharmony_ci}
327141cc406Sopenharmony_ci
328141cc406Sopenharmony_cistatic SANE_Status
329141cc406Sopenharmony_ciRegisterSaneDev (TModel model, SANE_String_Const szName)
330141cc406Sopenharmony_ci{
331141cc406Sopenharmony_ci  TDevice * q;
332141cc406Sopenharmony_ci
333141cc406Sopenharmony_ci  errno = 0;
334141cc406Sopenharmony_ci
335141cc406Sopenharmony_ci  q = malloc (sizeof (*q));
336141cc406Sopenharmony_ci  if (!q)
337141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci  memset (q, 0, sizeof (*q)); /* clear every field */
340141cc406Sopenharmony_ci  q->szSaneName  = strdup (szName);
341141cc406Sopenharmony_ci  q->sane.name   = (SANE_String_Const) q->szSaneName;
342141cc406Sopenharmony_ci  q->sane.vendor = "Microtek";
343141cc406Sopenharmony_ci  q->sane.model  = "ScanMaker 3600";
344141cc406Sopenharmony_ci  q->sane.type   = "flatbed scanner";
345141cc406Sopenharmony_ci
346141cc406Sopenharmony_ci  q->model=model;
347141cc406Sopenharmony_ci
348141cc406Sopenharmony_ci  ++num_devices;
349141cc406Sopenharmony_ci  q->pNext = pdevFirst; /* link backwards */
350141cc406Sopenharmony_ci  pdevFirst = q;
351141cc406Sopenharmony_ci
352141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
353141cc406Sopenharmony_ci}
354141cc406Sopenharmony_ci
355141cc406Sopenharmony_cistatic SANE_Status
356141cc406Sopenharmony_cism_usb_attach (SANE_String_Const dev_name)
357141cc406Sopenharmony_ci{
358141cc406Sopenharmony_ci  int fd;
359141cc406Sopenharmony_ci  SANE_Status err;
360141cc406Sopenharmony_ci  SANE_Word v, p;
361141cc406Sopenharmony_ci  TModel model;
362141cc406Sopenharmony_ci
363141cc406Sopenharmony_ci  err = sanei_usb_open(dev_name, &fd);
364141cc406Sopenharmony_ci  if (err)
365141cc406Sopenharmony_ci    return err;
366141cc406Sopenharmony_ci  err = sanei_usb_get_vendor_product (fd, &v, &p);
367141cc406Sopenharmony_ci  if (err)
368141cc406Sopenharmony_ci    {
369141cc406Sopenharmony_ci      sanei_usb_close (fd);
370141cc406Sopenharmony_ci      return err;
371141cc406Sopenharmony_ci    }
372141cc406Sopenharmony_ci  DBG (DEBUG_JUNK, "found dev %04X/%04X, %s\n", v, p, dev_name);
373141cc406Sopenharmony_ci  model = GetScannerModel (v, p);
374141cc406Sopenharmony_ci  if (model != unknown)
375141cc406Sopenharmony_ci    RegisterSaneDev (model, dev_name);
376141cc406Sopenharmony_ci
377141cc406Sopenharmony_ci  sanei_usb_close(fd);
378141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
379141cc406Sopenharmony_ci}
380141cc406Sopenharmony_ci
381141cc406Sopenharmony_ciSANE_Status
382141cc406Sopenharmony_cisane_init (SANE_Int *version_code, SANE_Auth_Callback authCB)
383141cc406Sopenharmony_ci{
384141cc406Sopenharmony_ci  int                i;
385141cc406Sopenharmony_ci
386141cc406Sopenharmony_ci  DBG_INIT();
387141cc406Sopenharmony_ci
388141cc406Sopenharmony_ci  (void) authCB; /* compiler */
389141cc406Sopenharmony_ci
390141cc406Sopenharmony_ci  DBG(DEBUG_VERBOSE,"SM3600 init\n");
391141cc406Sopenharmony_ci  if (version_code)
392141cc406Sopenharmony_ci   {
393141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
394141cc406Sopenharmony_ci    DBG(DEBUG_VERBOSE,"SM3600 version: %x\n",
395141cc406Sopenharmony_ci    	SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD));
396141cc406Sopenharmony_ci   }
397141cc406Sopenharmony_ci
398141cc406Sopenharmony_ci  pdevFirst=NULL;
399141cc406Sopenharmony_ci
400141cc406Sopenharmony_ci  sanei_usb_init();
401141cc406Sopenharmony_ci  for (i = 0; aScanners[i].idProduct; i++)
402141cc406Sopenharmony_ci    {
403141cc406Sopenharmony_ci      sanei_usb_find_devices(SCANNER_VENDOR, aScanners[i].idProduct, sm_usb_attach);
404141cc406Sopenharmony_ci    }
405141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
406141cc406Sopenharmony_ci}
407141cc406Sopenharmony_ci
408141cc406Sopenharmony_cistatic const SANE_Device ** devlist = 0; /* only pseudo-statical */
409141cc406Sopenharmony_ci
410141cc406Sopenharmony_civoid
411141cc406Sopenharmony_cisane_exit (void)
412141cc406Sopenharmony_ci{
413141cc406Sopenharmony_ci  TDevice   *dev, *pNext;
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci  /* free all bound resources and instances */
416141cc406Sopenharmony_ci  while (pinstFirst)
417141cc406Sopenharmony_ci    sane_close((SANE_Handle)pinstFirst); /* free all resources */
418141cc406Sopenharmony_ci
419141cc406Sopenharmony_ci  /* free all device descriptors */
420141cc406Sopenharmony_ci  for (dev = pdevFirst; dev; dev = pNext)
421141cc406Sopenharmony_ci    {
422141cc406Sopenharmony_ci      pNext = dev->pNext;
423141cc406Sopenharmony_ci      free (dev->szSaneName);
424141cc406Sopenharmony_ci      free (dev);
425141cc406Sopenharmony_ci    }
426141cc406Sopenharmony_ci  if (devlist) free(devlist);
427141cc406Sopenharmony_ci  devlist=NULL;
428141cc406Sopenharmony_ci}
429141cc406Sopenharmony_ci
430141cc406Sopenharmony_ciSANE_Status
431141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list,
432141cc406Sopenharmony_ci		  SANE_Bool __sane_unused__ local_only)
433141cc406Sopenharmony_ci{
434141cc406Sopenharmony_ci  TDevice *dev;
435141cc406Sopenharmony_ci  int i;
436141cc406Sopenharmony_ci
437141cc406Sopenharmony_ci  if (devlist) free (devlist);
438141cc406Sopenharmony_ci
439141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
440141cc406Sopenharmony_ci  if (!devlist)
441141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
442141cc406Sopenharmony_ci
443141cc406Sopenharmony_ci  i = 0;
444141cc406Sopenharmony_ci  for (dev = pdevFirst; i < num_devices; dev = dev->pNext)
445141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
446141cc406Sopenharmony_ci  devlist[i++] = 0;
447141cc406Sopenharmony_ci
448141cc406Sopenharmony_ci  *device_list = devlist;
449141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
450141cc406Sopenharmony_ci}
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ciSANE_Status
453141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle *handle)
454141cc406Sopenharmony_ci{
455141cc406Sopenharmony_ci  TDevice    *pdev;
456141cc406Sopenharmony_ci  TInstance  *this;
457141cc406Sopenharmony_ci  DBG(DEBUG_VERBOSE,"opening %s\n",devicename);
458141cc406Sopenharmony_ci  if (devicename[0]) /* selected */
459141cc406Sopenharmony_ci    {
460141cc406Sopenharmony_ci      for (pdev=pdevFirst; pdev; pdev=pdev->pNext)
461141cc406Sopenharmony_ci{
462141cc406Sopenharmony_ciDBG(DEBUG_VERBOSE,"%s<>%s\n",devicename, pdev->sane.name);
463141cc406Sopenharmony_ci	if (!strcmp(devicename,pdev->sane.name))
464141cc406Sopenharmony_ci	  break;
465141cc406Sopenharmony_ci}
466141cc406Sopenharmony_ci      /* no dynamic post-registration */
467141cc406Sopenharmony_ci    }
468141cc406Sopenharmony_ci  else
469141cc406Sopenharmony_ci    pdev=pdevFirst;
470141cc406Sopenharmony_ci  if (!pdev)
471141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
472141cc406Sopenharmony_ci  this = (TInstance*) calloc(1,sizeof(TInstance));
473141cc406Sopenharmony_ci  if (!this) return SANE_STATUS_NO_MEM;
474141cc406Sopenharmony_ci
475141cc406Sopenharmony_ci  *handle = (SANE_Handle)this;
476141cc406Sopenharmony_ci
477141cc406Sopenharmony_ci  ResetCalibration(this); /* do not release memory */
478141cc406Sopenharmony_ci  this->pNext=pinstFirst; /* register open handle */
479141cc406Sopenharmony_ci  pinstFirst=this;
480141cc406Sopenharmony_ci  this->model=pdev->model; /* memorize model */
481141cc406Sopenharmony_ci  /* open and prepare USB scanner handle */
482141cc406Sopenharmony_ci
483141cc406Sopenharmony_ci  if (sanei_usb_open (devicename, &this->hScanner) != SANE_STATUS_GOOD)
484141cc406Sopenharmony_ci    return SetError (this, SANE_STATUS_IO_ERROR, "cannot open scanner device");
485141cc406Sopenharmony_ci
486141cc406Sopenharmony_ci  this->quality=fast;
487141cc406Sopenharmony_ci  return InitOptions(this);
488141cc406Sopenharmony_ci}
489141cc406Sopenharmony_ci
490141cc406Sopenharmony_civoid
491141cc406Sopenharmony_cisane_close (SANE_Handle handle)
492141cc406Sopenharmony_ci{
493141cc406Sopenharmony_ci  TInstance *this,*pParent,*p;
494141cc406Sopenharmony_ci  this=(TInstance*)handle;
495141cc406Sopenharmony_ci  DBG(DEBUG_VERBOSE,"closing scanner\n");
496141cc406Sopenharmony_ci  if (this->hScanner)
497141cc406Sopenharmony_ci    {
498141cc406Sopenharmony_ci      if (this->state.bScanning)
499141cc406Sopenharmony_ci	EndScan(this);
500141cc406Sopenharmony_ci
501141cc406Sopenharmony_ci      sanei_usb_close(this->hScanner);
502141cc406Sopenharmony_ci      this->hScanner=-1;
503141cc406Sopenharmony_ci    }
504141cc406Sopenharmony_ci  ResetCalibration(this); /* release calibration data */
505141cc406Sopenharmony_ci  /* unlink active device entry */
506141cc406Sopenharmony_ci  pParent=NULL;
507141cc406Sopenharmony_ci  for (p=pinstFirst; p; p=p->pNext)
508141cc406Sopenharmony_ci    {
509141cc406Sopenharmony_ci      if (p==this) break;
510141cc406Sopenharmony_ci      pParent=p;
511141cc406Sopenharmony_ci    }
512141cc406Sopenharmony_ci
513141cc406Sopenharmony_ci  if (!p)
514141cc406Sopenharmony_ci    {
515141cc406Sopenharmony_ci      DBG(1,"invalid handle in close()\n");
516141cc406Sopenharmony_ci      return;
517141cc406Sopenharmony_ci    }
518141cc406Sopenharmony_ci  /* delete instance from instance list */
519141cc406Sopenharmony_ci  if (pParent)
520141cc406Sopenharmony_ci    pParent->pNext=this->pNext;
521141cc406Sopenharmony_ci  else
522141cc406Sopenharmony_ci    pinstFirst=this->pNext; /* NULL with last entry */
523141cc406Sopenharmony_ci  /* free resources */
524141cc406Sopenharmony_ci  if (this->pchPageBuffer)
525141cc406Sopenharmony_ci    free(this->pchPageBuffer);
526141cc406Sopenharmony_ci  if (this->szErrorReason)
527141cc406Sopenharmony_ci    {
528141cc406Sopenharmony_ci      DBG(DEBUG_VERBOSE,"Error status: %d, %s",
529141cc406Sopenharmony_ci	  this->nErrorState, this->szErrorReason);
530141cc406Sopenharmony_ci      free(this->szErrorReason);
531141cc406Sopenharmony_ci    }
532141cc406Sopenharmony_ci  free(this);
533141cc406Sopenharmony_ci}
534141cc406Sopenharmony_ci
535141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
536141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int iOpt)
537141cc406Sopenharmony_ci{
538141cc406Sopenharmony_ci  TInstance *this=(TInstance*)handle;
539141cc406Sopenharmony_ci  if (iOpt<NUM_OPTIONS)
540141cc406Sopenharmony_ci    return this->aoptDesc+iOpt;
541141cc406Sopenharmony_ci  return NULL;
542141cc406Sopenharmony_ci}
543141cc406Sopenharmony_ci
544141cc406Sopenharmony_ciSANE_Status
545141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int iOpt,
546141cc406Sopenharmony_ci		     SANE_Action action, void *pVal,
547141cc406Sopenharmony_ci		     SANE_Int *pnInfo)
548141cc406Sopenharmony_ci{
549141cc406Sopenharmony_ci  SANE_Word   cap;
550141cc406Sopenharmony_ci  SANE_Status rc;
551141cc406Sopenharmony_ci  TInstance *this;
552141cc406Sopenharmony_ci  this=(TInstance*)handle;
553141cc406Sopenharmony_ci  rc=SANE_STATUS_GOOD;
554141cc406Sopenharmony_ci  if (pnInfo)
555141cc406Sopenharmony_ci    *pnInfo=0;
556141cc406Sopenharmony_ci
557141cc406Sopenharmony_ci  if (this->state.bScanning)
558141cc406Sopenharmony_ci    return SANE_STATUS_DEVICE_BUSY;
559141cc406Sopenharmony_ci  if (iOpt>=NUM_OPTIONS)
560141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
561141cc406Sopenharmony_ci
562141cc406Sopenharmony_ci  cap=this->aoptDesc[iOpt].cap;
563141cc406Sopenharmony_ci
564141cc406Sopenharmony_ci  switch (action)
565141cc406Sopenharmony_ci    {
566141cc406Sopenharmony_ci
567141cc406Sopenharmony_ci      /* ------------------------------------------------------------ */
568141cc406Sopenharmony_ci
569141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
570141cc406Sopenharmony_ci      switch ((TOptionIndex)iOpt)
571141cc406Sopenharmony_ci	{
572141cc406Sopenharmony_ci	case optCount:
573141cc406Sopenharmony_ci	case optPreview:
574141cc406Sopenharmony_ci	case optGrayPreview:
575141cc406Sopenharmony_ci	case optResolution:
576141cc406Sopenharmony_ci#ifdef SM3600_SUPPORT_EXPOSURE
577141cc406Sopenharmony_ci	case optBrightness:
578141cc406Sopenharmony_ci	case optContrast:
579141cc406Sopenharmony_ci#endif
580141cc406Sopenharmony_ci	case optTLX: case optTLY: case optBRX: case optBRY:
581141cc406Sopenharmony_ci	  *(SANE_Word*)pVal = this->aoptVal[iOpt].w;
582141cc406Sopenharmony_ci	  break;
583141cc406Sopenharmony_ci	case optMode:
584141cc406Sopenharmony_ci	  strcpy(pVal,this->aoptVal[iOpt].s);
585141cc406Sopenharmony_ci	  break;
586141cc406Sopenharmony_ci	case optGammaY:
587141cc406Sopenharmony_ci	case optGammaR:
588141cc406Sopenharmony_ci	case optGammaG:
589141cc406Sopenharmony_ci	case optGammaB:
590141cc406Sopenharmony_ci	  DBG(DEBUG_INFO,"getting gamma\n");
591141cc406Sopenharmony_ci	  memcpy(pVal,this->aoptVal[iOpt].wa, this->aoptDesc[iOpt].size);
592141cc406Sopenharmony_ci	  break;
593141cc406Sopenharmony_ci	default:
594141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
595141cc406Sopenharmony_ci	}
596141cc406Sopenharmony_ci      break;
597141cc406Sopenharmony_ci
598141cc406Sopenharmony_ci      /* ------------------------------------------------------------ */
599141cc406Sopenharmony_ci
600141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
601141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE(cap))
602141cc406Sopenharmony_ci	return SANE_STATUS_INVAL;
603141cc406Sopenharmony_ci      rc=sanei_constrain_value(this->aoptDesc+iOpt,pVal,pnInfo);
604141cc406Sopenharmony_ci      if (rc!=SANE_STATUS_GOOD)
605141cc406Sopenharmony_ci	return rc;
606141cc406Sopenharmony_ci      switch ((TOptionIndex)iOpt)
607141cc406Sopenharmony_ci	{
608141cc406Sopenharmony_ci	case optResolution:
609141cc406Sopenharmony_ci	case optTLX: case optTLY: case optBRX: case optBRY:
610141cc406Sopenharmony_ci          if (pnInfo) (*pnInfo) |= SANE_INFO_RELOAD_PARAMS;
611141cc406Sopenharmony_ci          // fall through
612141cc406Sopenharmony_ci	case optPreview:
613141cc406Sopenharmony_ci	case optGrayPreview:
614141cc406Sopenharmony_ci#ifdef SM3600_SUPPORT_EXPOSURE
615141cc406Sopenharmony_ci	case optBrightness:
616141cc406Sopenharmony_ci	case optContrast:
617141cc406Sopenharmony_ci#endif
618141cc406Sopenharmony_ci	  this->aoptVal[iOpt].w = *(SANE_Word*)pVal;
619141cc406Sopenharmony_ci	  break;
620141cc406Sopenharmony_ci	case optMode:
621141cc406Sopenharmony_ci	  if (pnInfo)
622141cc406Sopenharmony_ci	    (*pnInfo) |= SANE_INFO_RELOAD_PARAMS
623141cc406Sopenharmony_ci	      | SANE_INFO_RELOAD_OPTIONS;
624141cc406Sopenharmony_ci	  strcpy(this->aoptVal[iOpt].s,pVal);
625141cc406Sopenharmony_ci	  break;
626141cc406Sopenharmony_ci	case optGammaY:
627141cc406Sopenharmony_ci	case optGammaR:	case optGammaG:	case optGammaB:
628141cc406Sopenharmony_ci	  DBG(DEBUG_INFO,"setting gamma #%d\n",iOpt);
629141cc406Sopenharmony_ci	  memcpy(this->aoptVal[iOpt].wa, pVal, this->aoptDesc[iOpt].size);
630141cc406Sopenharmony_ci	  break;
631141cc406Sopenharmony_ci	default:
632141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
633141cc406Sopenharmony_ci	}
634141cc406Sopenharmony_ci      break;
635141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
636141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
637141cc406Sopenharmony_ci    } /* switch action */
638141cc406Sopenharmony_ci  return rc; /* normally GOOD */
639141cc406Sopenharmony_ci}
640141cc406Sopenharmony_ci
641141cc406Sopenharmony_cistatic SANE_Status
642141cc406Sopenharmony_ciSetupInternalParameters(TInstance *this)
643141cc406Sopenharmony_ci{
644141cc406Sopenharmony_ci  int         i;
645141cc406Sopenharmony_ci  this->param.res=(int)this->aoptVal[optResolution].w;
646141cc406Sopenharmony_ci#ifdef SM3600_SUPPORT_EXPOSURE
647141cc406Sopenharmony_ci  this->param.nBrightness=(int)(this->aoptVal[optBrightness].w>>SANE_FIXED_SCALE_SHIFT);
648141cc406Sopenharmony_ci  this->param.nContrast=(int)(this->aoptVal[optContrast].w>>SANE_FIXED_SCALE_SHIFT);
649141cc406Sopenharmony_ci#else
650141cc406Sopenharmony_ci  this->param.nBrightness=0;
651141cc406Sopenharmony_ci  this->param.nContrast=0;
652141cc406Sopenharmony_ci#endif
653141cc406Sopenharmony_ci  this->param.x=(int)(SANE_UNFIX(this->aoptVal[optTLX].w)*1200.0/25.4);
654141cc406Sopenharmony_ci  this->param.y=(int)(SANE_UNFIX(this->aoptVal[optTLY].w)*1200.0/25.4);
655141cc406Sopenharmony_ci  this->param.cx=(int)(SANE_UNFIX(this->aoptVal[optBRX].w-this->aoptVal[optTLX].w)*1200.0/25.4)+1;
656141cc406Sopenharmony_ci  this->param.cy=(int)(SANE_UNFIX(this->aoptVal[optBRY].w-this->aoptVal[optTLY].w)*1200.0/25.4)+1;
657141cc406Sopenharmony_ci  for (i=0; aScanModes[i]; i++)
658141cc406Sopenharmony_ci    if (!strcasecmp(this->aoptVal[optMode].s,aScanModes[i]))
659141cc406Sopenharmony_ci      {
660141cc406Sopenharmony_ci	this->mode=(TMode)i;
661141cc406Sopenharmony_ci	break;
662141cc406Sopenharmony_ci      }
663141cc406Sopenharmony_ci  DBG(DEBUG_INFO,"mode=%d, res=%d, BC=[%d,%d], xywh=[%d,%d,%d,%d]\n",
664141cc406Sopenharmony_ci      this->mode, this->param.res,
665141cc406Sopenharmony_ci      this->param.nBrightness, this->param.nContrast,
666141cc406Sopenharmony_ci      this->param.x,this->param.y,this->param.cx,this->param.cy);
667141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
668141cc406Sopenharmony_ci}
669141cc406Sopenharmony_ci
670141cc406Sopenharmony_ciSANE_Status
671141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters *p)
672141cc406Sopenharmony_ci{
673141cc406Sopenharmony_ci  /* extremely important for xscanimage */
674141cc406Sopenharmony_ci  TInstance *this;
675141cc406Sopenharmony_ci  this=(TInstance*)handle;
676141cc406Sopenharmony_ci  SetupInternalParameters(this);
677141cc406Sopenharmony_ci  GetAreaSize(this);
678141cc406Sopenharmony_ci  p->pixels_per_line=this->state.cxPixel;
679141cc406Sopenharmony_ci  /* TODO: we need a more stable cyPixel prediction */
680141cc406Sopenharmony_ci  p->lines=this->state.cyPixel;
681141cc406Sopenharmony_ci  p->last_frame=SANE_TRUE;
682141cc406Sopenharmony_ci  switch (this->mode)
683141cc406Sopenharmony_ci    {
684141cc406Sopenharmony_ci    case color:
685141cc406Sopenharmony_ci      p->format=SANE_FRAME_RGB;
686141cc406Sopenharmony_ci      p->depth=8;
687141cc406Sopenharmony_ci      p->bytes_per_line=p->pixels_per_line*3;
688141cc406Sopenharmony_ci      break;
689141cc406Sopenharmony_ci    case gray:
690141cc406Sopenharmony_ci      p->format=SANE_FRAME_GRAY;
691141cc406Sopenharmony_ci      p->depth=8;
692141cc406Sopenharmony_ci      p->bytes_per_line=p->pixels_per_line;
693141cc406Sopenharmony_ci      break;
694141cc406Sopenharmony_ci    case halftone:
695141cc406Sopenharmony_ci    case line:
696141cc406Sopenharmony_ci      p->format=SANE_FRAME_GRAY;
697141cc406Sopenharmony_ci      p->depth=1;
698141cc406Sopenharmony_ci      p->bytes_per_line=(p->pixels_per_line+7)/8;
699141cc406Sopenharmony_ci      break;
700141cc406Sopenharmony_ci    }
701141cc406Sopenharmony_ci  DBG(DEBUG_INFO,"getting parameters (%d,%d)...\n",p->bytes_per_line,p->lines);
702141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
703141cc406Sopenharmony_ci}
704141cc406Sopenharmony_ci
705141cc406Sopenharmony_ciSANE_Status
706141cc406Sopenharmony_cisane_start (SANE_Handle handle)
707141cc406Sopenharmony_ci{
708141cc406Sopenharmony_ci  TInstance    *this;
709141cc406Sopenharmony_ci  SANE_Status   rc;
710141cc406Sopenharmony_ci  this=(TInstance*)handle;
711141cc406Sopenharmony_ci  DBG(DEBUG_VERBOSE,"starting scan...\n");
712141cc406Sopenharmony_ci  if (this->state.bScanning) return SANE_STATUS_DEVICE_BUSY;
713141cc406Sopenharmony_ci  rc=SetupInternalParameters(this);
714141cc406Sopenharmony_ci  this->state.bCanceled=false;
715141cc406Sopenharmony_ci  if (!rc) rc=DoInit(this); /* oopsi, we should initialise :-) */
716141cc406Sopenharmony_ci  if (!rc && !this->bOptSkipOriginate) rc=DoOriginate(this,true);
717141cc406Sopenharmony_ci  if (!rc) rc=DoJog(this,this->calibration.yMargin);
718141cc406Sopenharmony_ci  if (rc) return rc;
719141cc406Sopenharmony_ci  this->state.bEOF=false;
720141cc406Sopenharmony_ci  switch (this->mode)
721141cc406Sopenharmony_ci    {
722141cc406Sopenharmony_ci    case color: rc=StartScanColor(this); break;
723141cc406Sopenharmony_ci    default:    rc=StartScanGray(this); break;
724141cc406Sopenharmony_ci    }
725141cc406Sopenharmony_ci  if (this->state.bCanceled) return SANE_STATUS_CANCELLED;
726141cc406Sopenharmony_ci  return rc;
727141cc406Sopenharmony_ci}
728141cc406Sopenharmony_ci
729141cc406Sopenharmony_ciSANE_Status
730141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte *puchBuffer,
731141cc406Sopenharmony_ci	   SANE_Int cchMax,
732141cc406Sopenharmony_ci	   SANE_Int *pcchRead)
733141cc406Sopenharmony_ci{
734141cc406Sopenharmony_ci  SANE_Status    rc;
735141cc406Sopenharmony_ci  TInstance     *this;
736141cc406Sopenharmony_ci  this=(TInstance*)handle;
737141cc406Sopenharmony_ci  DBG(DEBUG_INFO,"reading chunk %d...\n",(int)cchMax);
738141cc406Sopenharmony_ci  *pcchRead=0;
739141cc406Sopenharmony_ci  if (this->state.bEOF)
740141cc406Sopenharmony_ci    return SANE_STATUS_EOF;
741141cc406Sopenharmony_ci  rc=ReadChunk(this,puchBuffer,cchMax,pcchRead);
742141cc406Sopenharmony_ci  DBG(DEBUG_INFO,"... line %d (%d/%d)...\n",this->state.iLine,*pcchRead,rc);
743141cc406Sopenharmony_ci  switch (rc)
744141cc406Sopenharmony_ci    {
745141cc406Sopenharmony_ci    case SANE_STATUS_EOF:
746141cc406Sopenharmony_ci      this->state.bEOF=true; /* flag EOF on next read() */
747141cc406Sopenharmony_ci      rc=SANE_STATUS_GOOD;   /* we do not flag THIS block! */
748141cc406Sopenharmony_ci      break;
749141cc406Sopenharmony_ci    case SANE_STATUS_GOOD:
750141cc406Sopenharmony_ci      if (!*pcchRead) rc=SANE_STATUS_EOF;
751141cc406Sopenharmony_ci      break;
752141cc406Sopenharmony_ci    default:
753141cc406Sopenharmony_ci      break;
754141cc406Sopenharmony_ci    }
755141cc406Sopenharmony_ci  return rc;
756141cc406Sopenharmony_ci}
757141cc406Sopenharmony_ci
758141cc406Sopenharmony_civoid
759141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
760141cc406Sopenharmony_ci{
761141cc406Sopenharmony_ci  TInstance *this;
762141cc406Sopenharmony_ci  this=(TInstance*)handle;
763141cc406Sopenharmony_ci  DBG(DEBUG_VERBOSE,"cancel called...\n");
764141cc406Sopenharmony_ci  if (this->state.bScanning)
765141cc406Sopenharmony_ci    {
766141cc406Sopenharmony_ci      this->state.bCanceled=true;
767141cc406Sopenharmony_ci      if (this->state.bEOF) /* regular (fast) cancel */
768141cc406Sopenharmony_ci	{
769141cc406Sopenharmony_ci	  DBG(DEBUG_INFO,"regular end cancel\n");
770141cc406Sopenharmony_ci	  EndScan(this);
771141cc406Sopenharmony_ci	  DoJog(this,-this->calibration.yMargin);
772141cc406Sopenharmony_ci	}
773141cc406Sopenharmony_ci      else
774141cc406Sopenharmony_ci	{
775141cc406Sopenharmony_ci	  /* since Xsane does not continue scanning,
776141cc406Sopenharmony_ci	     we cannot defer cancellation */
777141cc406Sopenharmony_ci	  DBG(DEBUG_INFO,"hard cancel called...\n");
778141cc406Sopenharmony_ci	  CancelScan(this);
779141cc406Sopenharmony_ci	}
780141cc406Sopenharmony_ci    }
781141cc406Sopenharmony_ci}
782141cc406Sopenharmony_ci
783141cc406Sopenharmony_ciSANE_Status
784141cc406Sopenharmony_cisane_set_io_mode(SANE_Handle h, SANE_Bool m)
785141cc406Sopenharmony_ci{
786141cc406Sopenharmony_ci  (void) h;
787141cc406Sopenharmony_ci  if (m==SANE_TRUE) /* no non-blocking-mode */
788141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
789141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
790141cc406Sopenharmony_ci}
791141cc406Sopenharmony_ci
792141cc406Sopenharmony_ciSANE_Status
793141cc406Sopenharmony_cisane_get_select_fd(SANE_Handle handle, SANE_Int *fd)
794141cc406Sopenharmony_ci{
795141cc406Sopenharmony_ci  (void) handle; (void) fd;
796141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED; /* we have no file IO */
797141cc406Sopenharmony_ci}
798