1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2001, Marcio Luis Teixeira
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   Parts copyright (C) 1996, 1997 Andreas Beck
6141cc406Sopenharmony_ci   Parts copyright (C) 2000, 2001 Michael Herder <crapsite@gmx.net>
7141cc406Sopenharmony_ci   Parts copyright (C) 2001 Henning Meier-Geinitz <henning@meier-geinitz.de>
8141cc406Sopenharmony_ci   Parts copyright (C) 2006 Patrick Lessard
9141cc406Sopenharmony_ci
10141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
11141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
12141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
13141cc406Sopenharmony_ci   License, or (at your option) any later version.
14141cc406Sopenharmony_ci
15141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
16141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
17141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18141cc406Sopenharmony_ci   General Public License for more details.
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
21141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
22141cc406Sopenharmony_ci
23141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
24141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
25141cc406Sopenharmony_ci
26141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
27141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
28141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
29141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
30141cc406Sopenharmony_ci   account of linking the SANE library code into it.
31141cc406Sopenharmony_ci
32141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
33141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
34141cc406Sopenharmony_ci   License.
35141cc406Sopenharmony_ci
36141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
37141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
38141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
39141cc406Sopenharmony_ci
40141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
41141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
42141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.  */
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci#define BUILD 2
45141cc406Sopenharmony_ci#define MM_IN_INCH 25.4
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci#include "../include/sane/config.h"
48141cc406Sopenharmony_ci
49141cc406Sopenharmony_ci#include <stdlib.h>
50141cc406Sopenharmony_ci#include <string.h>
51141cc406Sopenharmony_ci#include <stdio.h>
52141cc406Sopenharmony_ci#include <unistd.h>
53141cc406Sopenharmony_ci#include <fcntl.h>
54141cc406Sopenharmony_ci#include <sys/ioctl.h>
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci#include "../include/sane/sane.h"
57141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
58141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
59141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
60141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
61141cc406Sopenharmony_ci#include "../include/sane/sanei_pv8630.h"
62141cc406Sopenharmony_ci
63141cc406Sopenharmony_ci#define BACKEND_NAME        umax1220u
64141cc406Sopenharmony_ci#define UMAX_CONFIG_FILE "umax1220u.conf"
65141cc406Sopenharmony_ci
66141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
67141cc406Sopenharmony_ci
68141cc406Sopenharmony_ci#include "umax1220u-common.c"
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_citypedef struct Umax_Device
71141cc406Sopenharmony_ci{
72141cc406Sopenharmony_ci  struct Umax_Device *next;
73141cc406Sopenharmony_ci  SANE_String name;
74141cc406Sopenharmony_ci  SANE_Device sane;
75141cc406Sopenharmony_ci}
76141cc406Sopenharmony_ciUmax_Device;
77141cc406Sopenharmony_ci
78141cc406Sopenharmony_citypedef struct Umax_Scanner
79141cc406Sopenharmony_ci{
80141cc406Sopenharmony_ci  struct Umax_Scanner *next;
81141cc406Sopenharmony_ci  Umax_Device *device;
82141cc406Sopenharmony_ci  UMAX_Handle scan;
83141cc406Sopenharmony_ci}
84141cc406Sopenharmony_ciUmax_Scanner;
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_cistatic int num_devices             = 0;
87141cc406Sopenharmony_cistatic const SANE_Device **devlist = NULL;
88141cc406Sopenharmony_cistatic Umax_Device *first_dev      = NULL;
89141cc406Sopenharmony_cistatic Umax_Scanner *first_handle  = NULL;
90141cc406Sopenharmony_ci
91141cc406Sopenharmony_cistatic SANE_Parameters parms = {
92141cc406Sopenharmony_ci  SANE_FRAME_RGB,
93141cc406Sopenharmony_ci  0,
94141cc406Sopenharmony_ci  0,                   /* Number of bytes returned per scan line: */
95141cc406Sopenharmony_ci  0,                   /* Number of pixels per scan line.  */
96141cc406Sopenharmony_ci  0,                   /* Number of lines for the current scan.  */
97141cc406Sopenharmony_ci  8                    /* Number of bits per sample. */
98141cc406Sopenharmony_ci};
99141cc406Sopenharmony_ci
100141cc406Sopenharmony_cistruct _SANE_Option
101141cc406Sopenharmony_ci{
102141cc406Sopenharmony_ci  SANE_Option_Descriptor *descriptor;
103141cc406Sopenharmony_ci  SANE_Status (*callback) (struct _SANE_Option * option, SANE_Handle handle,
104141cc406Sopenharmony_ci                           SANE_Action action, void *value,
105141cc406Sopenharmony_ci                           SANE_Int * info);
106141cc406Sopenharmony_ci};
107141cc406Sopenharmony_ci
108141cc406Sopenharmony_citypedef struct _SANE_Option SANE_Option;
109141cc406Sopenharmony_ci
110141cc406Sopenharmony_cistatic SANE_Word getNumberOfOptions (void);  /* Forward declaration */
111141cc406Sopenharmony_ci
112141cc406Sopenharmony_ci/*
113141cc406Sopenharmony_ciThis read-only option returns the number of options available for
114141cc406Sopenharmony_cithe device. It should be the first option in the options array
115141cc406Sopenharmony_cideclared below.
116141cc406Sopenharmony_ci*/
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_cistatic SANE_Option_Descriptor optionNumOptionsDescriptor = {
119141cc406Sopenharmony_ci  SANE_NAME_NUM_OPTIONS,
120141cc406Sopenharmony_ci  SANE_TITLE_NUM_OPTIONS,
121141cc406Sopenharmony_ci  SANE_DESC_NUM_OPTIONS,
122141cc406Sopenharmony_ci  SANE_TYPE_INT,
123141cc406Sopenharmony_ci  SANE_UNIT_NONE,
124141cc406Sopenharmony_ci  sizeof (SANE_Word),
125141cc406Sopenharmony_ci  SANE_CAP_SOFT_DETECT,
126141cc406Sopenharmony_ci  SANE_CONSTRAINT_NONE,
127141cc406Sopenharmony_ci  {NULL}
128141cc406Sopenharmony_ci};
129141cc406Sopenharmony_ci
130141cc406Sopenharmony_cistatic SANE_Status
131141cc406Sopenharmony_cioptionNumOptionsCallback (SANE_Option * option, SANE_Handle handle,
132141cc406Sopenharmony_ci                          SANE_Action action, void *value, SANE_Int * info)
133141cc406Sopenharmony_ci{
134141cc406Sopenharmony_ci  (void) option;
135141cc406Sopenharmony_ci  (void) handle;
136141cc406Sopenharmony_ci  (void) info;                  /* Eliminate warning about unused parameters */
137141cc406Sopenharmony_ci
138141cc406Sopenharmony_ci  if (action != SANE_ACTION_GET_VALUE)
139141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
140141cc406Sopenharmony_ci  *(SANE_Word *) value = getNumberOfOptions ();
141141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
142141cc406Sopenharmony_ci}
143141cc406Sopenharmony_ci
144141cc406Sopenharmony_ci/*
145141cc406Sopenharmony_ciThis option lets the user select the scan resolution. The UMAX
146141cc406Sopenharmony_ciscanner only supports the following resolutions: 75, 150, 300 and
147141cc406Sopenharmony_ci600
148141cc406Sopenharmony_ci*/
149141cc406Sopenharmony_ci
150141cc406Sopenharmony_cistatic const SANE_Word optionResolutionList[] = {
151141cc406Sopenharmony_ci  4,                       /* Number of elements */
152141cc406Sopenharmony_ci  75, 150, 300, 600        /* Resolution list */
153141cc406Sopenharmony_ci};
154141cc406Sopenharmony_ci
155141cc406Sopenharmony_cistatic SANE_Option_Descriptor optionResolutionDescriptor = {
156141cc406Sopenharmony_ci  SANE_NAME_SCAN_RESOLUTION,
157141cc406Sopenharmony_ci  SANE_TITLE_SCAN_RESOLUTION,
158141cc406Sopenharmony_ci  SANE_DESC_SCAN_RESOLUTION,
159141cc406Sopenharmony_ci  SANE_TYPE_INT,
160141cc406Sopenharmony_ci  SANE_UNIT_DPI,
161141cc406Sopenharmony_ci  sizeof (SANE_Word),
162141cc406Sopenharmony_ci  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_AUTOMATIC,
163141cc406Sopenharmony_ci  SANE_CONSTRAINT_WORD_LIST,
164141cc406Sopenharmony_ci  {(const SANE_String_Const *) optionResolutionList}
165141cc406Sopenharmony_ci};
166141cc406Sopenharmony_ci
167141cc406Sopenharmony_cistatic SANE_Word optionResolutionValue = 75;
168141cc406Sopenharmony_ci
169141cc406Sopenharmony_cistatic SANE_Status
170141cc406Sopenharmony_cioptionResolutionCallback (SANE_Option * option, SANE_Handle handle,
171141cc406Sopenharmony_ci                          SANE_Action action, void *value, SANE_Int * info)
172141cc406Sopenharmony_ci{
173141cc406Sopenharmony_ci  SANE_Status status;
174141cc406Sopenharmony_ci  SANE_Word autoValue = 75;
175141cc406Sopenharmony_ci
176141cc406Sopenharmony_ci  (void) handle;                /* Eliminate warning about unused parameters */
177141cc406Sopenharmony_ci
178141cc406Sopenharmony_ci  switch (action)
179141cc406Sopenharmony_ci    {
180141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
181141cc406Sopenharmony_ci      status =
182141cc406Sopenharmony_ci        sanei_constrain_value (option->descriptor, (void *) &autoValue, info);
183141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
184141cc406Sopenharmony_ci        return status;
185141cc406Sopenharmony_ci      optionResolutionValue = autoValue;
186141cc406Sopenharmony_ci      *info |= SANE_INFO_RELOAD_PARAMS;
187141cc406Sopenharmony_ci      break;
188141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
189141cc406Sopenharmony_ci      *info |= SANE_INFO_RELOAD_PARAMS;
190141cc406Sopenharmony_ci      optionResolutionValue = *(SANE_Word *) value;
191141cc406Sopenharmony_ci      break;
192141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
193141cc406Sopenharmony_ci      *(SANE_Word *) value = optionResolutionValue;
194141cc406Sopenharmony_ci      break;
195141cc406Sopenharmony_ci    }
196141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
197141cc406Sopenharmony_ci}
198141cc406Sopenharmony_ci
199141cc406Sopenharmony_ci/*
200141cc406Sopenharmony_ciThis option lets the user select a gray scale scan
201141cc406Sopenharmony_ci*/
202141cc406Sopenharmony_cistatic SANE_Word optionGrayscaleValue = SANE_FALSE;
203141cc406Sopenharmony_ci
204141cc406Sopenharmony_cistatic SANE_Option_Descriptor optionGrayscaleDescriptor = {
205141cc406Sopenharmony_ci  "gray",
206141cc406Sopenharmony_ci  SANE_I18N ("Grayscale scan"),
207141cc406Sopenharmony_ci  SANE_I18N ("Do a grayscale rather than color scan"),
208141cc406Sopenharmony_ci  SANE_TYPE_BOOL,
209141cc406Sopenharmony_ci  SANE_UNIT_NONE,
210141cc406Sopenharmony_ci  sizeof (SANE_Word),
211141cc406Sopenharmony_ci  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
212141cc406Sopenharmony_ci  SANE_CONSTRAINT_NONE,
213141cc406Sopenharmony_ci  {NULL}
214141cc406Sopenharmony_ci};
215141cc406Sopenharmony_ci
216141cc406Sopenharmony_cistatic SANE_Status
217141cc406Sopenharmony_cioptionGrayscaleCallback (SANE_Option * option, SANE_Handle handle,
218141cc406Sopenharmony_ci                         SANE_Action action, void *value, SANE_Int * info)
219141cc406Sopenharmony_ci{
220141cc406Sopenharmony_ci  (void) handle;
221141cc406Sopenharmony_ci  (void) option;                /* Eliminate warning about unused parameters */
222141cc406Sopenharmony_ci
223141cc406Sopenharmony_ci  switch (action)
224141cc406Sopenharmony_ci    {
225141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
226141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
227141cc406Sopenharmony_ci      break;
228141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
229141cc406Sopenharmony_ci      *info |= SANE_INFO_RELOAD_PARAMS;
230141cc406Sopenharmony_ci      optionGrayscaleValue = *(SANE_Bool *) value;
231141cc406Sopenharmony_ci      break;
232141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
233141cc406Sopenharmony_ci      *(SANE_Word *) value = optionGrayscaleValue;
234141cc406Sopenharmony_ci      break;
235141cc406Sopenharmony_ci    }
236141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
237141cc406Sopenharmony_ci}
238141cc406Sopenharmony_ci
239141cc406Sopenharmony_ci/*
240141cc406Sopenharmony_ciThis option is a button that allows the user to turn off the
241141cc406Sopenharmony_cilamp in the UMAX scanner
242141cc406Sopenharmony_ci*/
243141cc406Sopenharmony_ci
244141cc406Sopenharmony_cistatic SANE_Option_Descriptor optionLampOffDescriptor = {
245141cc406Sopenharmony_ci  "lamp-off",
246141cc406Sopenharmony_ci  SANE_I18N ("Lamp off"),
247141cc406Sopenharmony_ci  SANE_I18N ("Turn off scanner lamp"),
248141cc406Sopenharmony_ci  SANE_TYPE_BUTTON,
249141cc406Sopenharmony_ci  SANE_UNIT_NONE,
250141cc406Sopenharmony_ci  0,
251141cc406Sopenharmony_ci  SANE_CAP_SOFT_SELECT,
252141cc406Sopenharmony_ci  SANE_CONSTRAINT_NONE,
253141cc406Sopenharmony_ci  {NULL}
254141cc406Sopenharmony_ci};
255141cc406Sopenharmony_ci
256141cc406Sopenharmony_cistatic SANE_Status
257141cc406Sopenharmony_cioptionLampOffCallback (SANE_Option * option, SANE_Handle handle,
258141cc406Sopenharmony_ci                       SANE_Action action, void *value, SANE_Int * info)
259141cc406Sopenharmony_ci{
260141cc406Sopenharmony_ci  Umax_Scanner *scanner = handle;
261141cc406Sopenharmony_ci  SANE_Status res = SANE_STATUS_GOOD;
262141cc406Sopenharmony_ci
263141cc406Sopenharmony_ci  /* Eliminate warnings about unused parameters */
264141cc406Sopenharmony_ci  (void) option;
265141cc406Sopenharmony_ci  (void) handle;
266141cc406Sopenharmony_ci  (void) info;
267141cc406Sopenharmony_ci  (void) value;
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci  if (action != SANE_ACTION_SET_VALUE)
270141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
271141cc406Sopenharmony_ci
272141cc406Sopenharmony_ci  res = UMAX_set_lamp_state (&scanner->scan, UMAX_LAMP_OFF);
273141cc406Sopenharmony_ci
274141cc406Sopenharmony_ci  return res;
275141cc406Sopenharmony_ci}
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_cistatic const SANE_Range widthRange = {
278141cc406Sopenharmony_ci  0,                                              /* minimum */
279141cc406Sopenharmony_ci  SANE_FIX (UMAX_MAX_WIDTH * MM_IN_INCH / 600),   /* maximum */
280141cc406Sopenharmony_ci  0                                               /* quantization */
281141cc406Sopenharmony_ci};
282141cc406Sopenharmony_ci
283141cc406Sopenharmony_cistatic const SANE_Range heightRange = {
284141cc406Sopenharmony_ci  0,                                              /* minimum */
285141cc406Sopenharmony_ci  SANE_FIX (UMAX_MAX_HEIGHT * MM_IN_INCH / 600),  /* maximum */
286141cc406Sopenharmony_ci  0                                               /* quantization */
287141cc406Sopenharmony_ci};
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_ci/*
290141cc406Sopenharmony_ciThis option controls the top-left-x corner of the scan
291141cc406Sopenharmony_ci*/
292141cc406Sopenharmony_ci
293141cc406Sopenharmony_cistatic SANE_Fixed optionTopLeftXValue = 0;
294141cc406Sopenharmony_ci
295141cc406Sopenharmony_cistatic SANE_Option_Descriptor optionTopLeftXDescriptor = {
296141cc406Sopenharmony_ci  SANE_NAME_SCAN_TL_X,
297141cc406Sopenharmony_ci  SANE_TITLE_SCAN_TL_X,
298141cc406Sopenharmony_ci  SANE_DESC_SCAN_TL_X,
299141cc406Sopenharmony_ci  SANE_TYPE_FIXED,
300141cc406Sopenharmony_ci  SANE_UNIT_MM,
301141cc406Sopenharmony_ci  sizeof (SANE_Fixed),
302141cc406Sopenharmony_ci  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
303141cc406Sopenharmony_ci  SANE_CONSTRAINT_RANGE,
304141cc406Sopenharmony_ci  {(const SANE_String_Const *) & widthRange}
305141cc406Sopenharmony_ci};
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_cistatic SANE_Status
308141cc406Sopenharmony_cioptionTopLeftXCallback (SANE_Option * option, SANE_Handle handle,
309141cc406Sopenharmony_ci                        SANE_Action action, void *value, SANE_Int * info)
310141cc406Sopenharmony_ci{
311141cc406Sopenharmony_ci  (void) option;
312141cc406Sopenharmony_ci  (void) handle;
313141cc406Sopenharmony_ci  (void) value;                 /* Eliminate warning about unused parameters */
314141cc406Sopenharmony_ci
315141cc406Sopenharmony_ci  switch (action)
316141cc406Sopenharmony_ci    {
317141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
318141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
319141cc406Sopenharmony_ci      break;
320141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
321141cc406Sopenharmony_ci      optionTopLeftXValue = *(SANE_Fixed *) value;
322141cc406Sopenharmony_ci      *info |= SANE_INFO_RELOAD_PARAMS;
323141cc406Sopenharmony_ci      break;
324141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
325141cc406Sopenharmony_ci      *(SANE_Fixed *) value = optionTopLeftXValue;
326141cc406Sopenharmony_ci      break;
327141cc406Sopenharmony_ci    }
328141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
329141cc406Sopenharmony_ci}
330141cc406Sopenharmony_ci
331141cc406Sopenharmony_ci/*
332141cc406Sopenharmony_ciThis option controls the top-left-y corner of the scan
333141cc406Sopenharmony_ci*/
334141cc406Sopenharmony_ci
335141cc406Sopenharmony_cistatic SANE_Fixed optionTopLeftYValue = 0;
336141cc406Sopenharmony_ci
337141cc406Sopenharmony_cistatic SANE_Option_Descriptor optionTopLeftYDescriptor = {
338141cc406Sopenharmony_ci  SANE_NAME_SCAN_TL_Y,
339141cc406Sopenharmony_ci  SANE_TITLE_SCAN_TL_Y,
340141cc406Sopenharmony_ci  SANE_DESC_SCAN_TL_Y,
341141cc406Sopenharmony_ci  SANE_TYPE_FIXED,
342141cc406Sopenharmony_ci  SANE_UNIT_MM,
343141cc406Sopenharmony_ci  sizeof (SANE_Fixed),
344141cc406Sopenharmony_ci  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
345141cc406Sopenharmony_ci  SANE_CONSTRAINT_RANGE,
346141cc406Sopenharmony_ci  {(const SANE_String_Const *) & heightRange}
347141cc406Sopenharmony_ci};
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_cistatic SANE_Status
350141cc406Sopenharmony_cioptionTopLeftYCallback (SANE_Option * option, SANE_Handle handle,
351141cc406Sopenharmony_ci                        SANE_Action action, void *value, SANE_Int * info)
352141cc406Sopenharmony_ci{
353141cc406Sopenharmony_ci  /* Eliminate warnings about unused parameters */
354141cc406Sopenharmony_ci  (void) option;
355141cc406Sopenharmony_ci  (void) handle;
356141cc406Sopenharmony_ci
357141cc406Sopenharmony_ci  switch (action)
358141cc406Sopenharmony_ci    {
359141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
360141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
361141cc406Sopenharmony_ci      break;
362141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
363141cc406Sopenharmony_ci      optionTopLeftYValue = *(SANE_Fixed *) value;
364141cc406Sopenharmony_ci      *info |= SANE_INFO_RELOAD_PARAMS;
365141cc406Sopenharmony_ci      break;
366141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
367141cc406Sopenharmony_ci      *(SANE_Fixed *) value = optionTopLeftYValue;
368141cc406Sopenharmony_ci      break;
369141cc406Sopenharmony_ci    }
370141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
371141cc406Sopenharmony_ci}
372141cc406Sopenharmony_ci
373141cc406Sopenharmony_ci/*
374141cc406Sopenharmony_ciThis option controls the bot-right-x corner of the scan
375141cc406Sopenharmony_ci*/
376141cc406Sopenharmony_ci
377141cc406Sopenharmony_cistatic SANE_Fixed optionBotRightXValue
378141cc406Sopenharmony_ci  = SANE_FIX (UMAX_MAX_WIDTH * MM_IN_INCH / 600);
379141cc406Sopenharmony_ci
380141cc406Sopenharmony_cistatic SANE_Option_Descriptor optionBotRightXDescriptor = {
381141cc406Sopenharmony_ci  SANE_NAME_SCAN_BR_X,
382141cc406Sopenharmony_ci  SANE_TITLE_SCAN_BR_X,
383141cc406Sopenharmony_ci  SANE_DESC_SCAN_BR_X,
384141cc406Sopenharmony_ci  SANE_TYPE_FIXED,
385141cc406Sopenharmony_ci  SANE_UNIT_MM,
386141cc406Sopenharmony_ci  sizeof (SANE_Fixed),
387141cc406Sopenharmony_ci  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
388141cc406Sopenharmony_ci  SANE_CONSTRAINT_RANGE,
389141cc406Sopenharmony_ci  {(const SANE_String_Const *) & widthRange}
390141cc406Sopenharmony_ci};
391141cc406Sopenharmony_ci
392141cc406Sopenharmony_cistatic SANE_Status
393141cc406Sopenharmony_cioptionBotRightXCallback (SANE_Option * option, SANE_Handle handle,
394141cc406Sopenharmony_ci                         SANE_Action action, void *value, SANE_Int * info)
395141cc406Sopenharmony_ci{
396141cc406Sopenharmony_ci  /* Eliminate warnings about unused parameters */
397141cc406Sopenharmony_ci  (void) option;
398141cc406Sopenharmony_ci  (void) handle;
399141cc406Sopenharmony_ci
400141cc406Sopenharmony_ci  switch (action)
401141cc406Sopenharmony_ci    {
402141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
403141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
404141cc406Sopenharmony_ci      break;
405141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
406141cc406Sopenharmony_ci      optionBotRightXValue = *(SANE_Fixed *) value;
407141cc406Sopenharmony_ci      *info |= SANE_INFO_RELOAD_PARAMS;
408141cc406Sopenharmony_ci      break;
409141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
410141cc406Sopenharmony_ci      *(SANE_Fixed *) value = optionBotRightXValue;
411141cc406Sopenharmony_ci      break;
412141cc406Sopenharmony_ci    }
413141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
414141cc406Sopenharmony_ci}
415141cc406Sopenharmony_ci
416141cc406Sopenharmony_ci/*
417141cc406Sopenharmony_ciThis option controls the bot-right-y corner of the scan
418141cc406Sopenharmony_ci*/
419141cc406Sopenharmony_ci
420141cc406Sopenharmony_cistatic SANE_Fixed optionBotRightYValue
421141cc406Sopenharmony_ci  = SANE_FIX (UMAX_MAX_HEIGHT * MM_IN_INCH / 600);
422141cc406Sopenharmony_ci
423141cc406Sopenharmony_cistatic SANE_Option_Descriptor optionBotRightYDescriptor = {
424141cc406Sopenharmony_ci  SANE_NAME_SCAN_BR_Y,
425141cc406Sopenharmony_ci  SANE_TITLE_SCAN_BR_Y,
426141cc406Sopenharmony_ci  SANE_DESC_SCAN_BR_Y,
427141cc406Sopenharmony_ci  SANE_TYPE_FIXED,
428141cc406Sopenharmony_ci  SANE_UNIT_MM,
429141cc406Sopenharmony_ci  sizeof (SANE_Fixed),
430141cc406Sopenharmony_ci  SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
431141cc406Sopenharmony_ci  SANE_CONSTRAINT_RANGE,
432141cc406Sopenharmony_ci  {(const SANE_String_Const *) & heightRange}
433141cc406Sopenharmony_ci};
434141cc406Sopenharmony_ci
435141cc406Sopenharmony_cistatic SANE_Status
436141cc406Sopenharmony_cioptionBotRightYCallback (SANE_Option * option, SANE_Handle handle,
437141cc406Sopenharmony_ci                         SANE_Action action, void *value, SANE_Int * info)
438141cc406Sopenharmony_ci{
439141cc406Sopenharmony_ci  /* Eliminate warnings about unused parameters */
440141cc406Sopenharmony_ci  (void) option;
441141cc406Sopenharmony_ci  (void) handle;
442141cc406Sopenharmony_ci
443141cc406Sopenharmony_ci  switch (action)
444141cc406Sopenharmony_ci    {
445141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
446141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
447141cc406Sopenharmony_ci      break;
448141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
449141cc406Sopenharmony_ci      optionBotRightYValue = *(SANE_Fixed *) value;
450141cc406Sopenharmony_ci      *info |= SANE_INFO_RELOAD_PARAMS;
451141cc406Sopenharmony_ci      break;
452141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
453141cc406Sopenharmony_ci      *(SANE_Fixed *) value = optionBotRightYValue;
454141cc406Sopenharmony_ci      break;
455141cc406Sopenharmony_ci    }
456141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
457141cc406Sopenharmony_ci}
458141cc406Sopenharmony_ci
459141cc406Sopenharmony_ci/*
460141cc406Sopenharmony_ciThe following array binds the option descriptors to
461141cc406Sopenharmony_citheir respective callback routines
462141cc406Sopenharmony_ci*/
463141cc406Sopenharmony_ci
464141cc406Sopenharmony_cistatic SANE_Option so[] = {
465141cc406Sopenharmony_ci  {&optionNumOptionsDescriptor, optionNumOptionsCallback},
466141cc406Sopenharmony_ci  {&optionResolutionDescriptor, optionResolutionCallback},
467141cc406Sopenharmony_ci  {&optionGrayscaleDescriptor, optionGrayscaleCallback},
468141cc406Sopenharmony_ci  {&optionTopLeftXDescriptor, optionTopLeftXCallback},
469141cc406Sopenharmony_ci  {&optionTopLeftYDescriptor, optionTopLeftYCallback},
470141cc406Sopenharmony_ci  {&optionBotRightXDescriptor, optionBotRightXCallback},
471141cc406Sopenharmony_ci  {&optionBotRightYDescriptor, optionBotRightYCallback},
472141cc406Sopenharmony_ci  {&optionLampOffDescriptor, optionLampOffCallback}
473141cc406Sopenharmony_ci};
474141cc406Sopenharmony_ci
475141cc406Sopenharmony_cistatic SANE_Word
476141cc406Sopenharmony_cigetNumberOfOptions (void)
477141cc406Sopenharmony_ci{
478141cc406Sopenharmony_ci  return NELEMS (so);
479141cc406Sopenharmony_ci}
480141cc406Sopenharmony_ci
481141cc406Sopenharmony_ci/*
482141cc406Sopenharmony_ciThis routine dispatches the control message to the appropriate
483141cc406Sopenharmony_cicallback routine, it outght to be called by sane_control_option
484141cc406Sopenharmony_ciafter any driver specific validation.
485141cc406Sopenharmony_ci*/
486141cc406Sopenharmony_cistatic SANE_Status
487141cc406Sopenharmony_cidispatch_control_option (SANE_Handle handle, SANE_Int option,
488141cc406Sopenharmony_ci                         SANE_Action action, void *value, SANE_Int * info)
489141cc406Sopenharmony_ci{
490141cc406Sopenharmony_ci  SANE_Option *op = so + option;
491141cc406Sopenharmony_ci  SANE_Int myinfo = 0;
492141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
493141cc406Sopenharmony_ci
494141cc406Sopenharmony_ci  if (option < 0 || option >= NELEMS (so))
495141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;        /* Unknown option ... */
496141cc406Sopenharmony_ci
497141cc406Sopenharmony_ci  if ((action == SANE_ACTION_SET_VALUE) &&
498141cc406Sopenharmony_ci      ((op->descriptor->cap & SANE_CAP_SOFT_SELECT) == 0))
499141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
500141cc406Sopenharmony_ci
501141cc406Sopenharmony_ci  if ((action == SANE_ACTION_GET_VALUE) &&
502141cc406Sopenharmony_ci      ((op->descriptor->cap & SANE_CAP_SOFT_DETECT) == 0))
503141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
504141cc406Sopenharmony_ci
505141cc406Sopenharmony_ci  if ((action == SANE_ACTION_SET_AUTO) &&
506141cc406Sopenharmony_ci      ((op->descriptor->cap & SANE_CAP_AUTOMATIC) == 0))
507141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
508141cc406Sopenharmony_ci
509141cc406Sopenharmony_ci  if (action == SANE_ACTION_SET_VALUE)
510141cc406Sopenharmony_ci    {
511141cc406Sopenharmony_ci      status = sanei_constrain_value (op->descriptor, value, &myinfo);
512141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
513141cc406Sopenharmony_ci        return status;
514141cc406Sopenharmony_ci    }
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci  status = (op->callback) (op, handle, action, value, &myinfo);
517141cc406Sopenharmony_ci
518141cc406Sopenharmony_ci  if (info)
519141cc406Sopenharmony_ci    *info = myinfo;
520141cc406Sopenharmony_ci
521141cc406Sopenharmony_ci  return status;
522141cc406Sopenharmony_ci}
523141cc406Sopenharmony_ci
524141cc406Sopenharmony_cistatic SANE_Status
525141cc406Sopenharmony_ciattach_scanner (const char *devicename, Umax_Device ** devp)
526141cc406Sopenharmony_ci{
527141cc406Sopenharmony_ci  UMAX_Handle scan;
528141cc406Sopenharmony_ci  Umax_Device *dev;
529141cc406Sopenharmony_ci  SANE_Status status;
530141cc406Sopenharmony_ci
531141cc406Sopenharmony_ci  DBG (3, "attach_scanner: %s\n", devicename);
532141cc406Sopenharmony_ci
533141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
534141cc406Sopenharmony_ci    {
535141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devicename) == 0)
536141cc406Sopenharmony_ci        {
537141cc406Sopenharmony_ci          if (devp)
538141cc406Sopenharmony_ci            *devp = dev;
539141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
540141cc406Sopenharmony_ci        }
541141cc406Sopenharmony_ci    }
542141cc406Sopenharmony_ci
543141cc406Sopenharmony_ci  dev = malloc (sizeof (*dev));
544141cc406Sopenharmony_ci  if (!dev)
545141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
546141cc406Sopenharmony_ci  memset (dev, '\0', sizeof (Umax_Device));        /* clear structure */
547141cc406Sopenharmony_ci
548141cc406Sopenharmony_ci  DBG (4, "attach_scanner: opening %s\n", devicename);
549141cc406Sopenharmony_ci
550141cc406Sopenharmony_ci  status = UMAX_open_device (&scan, devicename);
551141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
552141cc406Sopenharmony_ci    {
553141cc406Sopenharmony_ci      DBG (1, "ERROR: attach_scanner: opening %s failed\n", devicename);
554141cc406Sopenharmony_ci      free (dev);
555141cc406Sopenharmony_ci      return status;
556141cc406Sopenharmony_ci    }
557141cc406Sopenharmony_ci  dev->name = strdup (devicename);
558141cc406Sopenharmony_ci  dev->sane.name = dev->name;
559141cc406Sopenharmony_ci  dev->sane.vendor = "UMAX";
560141cc406Sopenharmony_ci  dev->sane.model = UMAX_get_device_name (&scan);
561141cc406Sopenharmony_ci  dev->sane.type = "flatbed scanner";
562141cc406Sopenharmony_ci  UMAX_close_device (&scan);
563141cc406Sopenharmony_ci
564141cc406Sopenharmony_ci  ++num_devices;
565141cc406Sopenharmony_ci  dev->next = first_dev;
566141cc406Sopenharmony_ci  first_dev = dev;
567141cc406Sopenharmony_ci
568141cc406Sopenharmony_ci  if (devp)
569141cc406Sopenharmony_ci    *devp = dev;
570141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
571141cc406Sopenharmony_ci}
572141cc406Sopenharmony_ci
573141cc406Sopenharmony_ci/* callback function for sanei_usb_attach_matching_devices
574141cc406Sopenharmony_ci*/
575141cc406Sopenharmony_cistatic SANE_Status
576141cc406Sopenharmony_ciattach_one (const char *name)
577141cc406Sopenharmony_ci{
578141cc406Sopenharmony_ci  attach_scanner (name, 0);
579141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
580141cc406Sopenharmony_ci}
581141cc406Sopenharmony_ci
582141cc406Sopenharmony_ci/* This file implements a SANE backend for the UMAX Astra 1220U scanner.
583141cc406Sopenharmony_ci */
584141cc406Sopenharmony_ciSANE_Status
585141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
586141cc406Sopenharmony_ci{
587141cc406Sopenharmony_ci  char config_line[PATH_MAX];
588141cc406Sopenharmony_ci  size_t len;
589141cc406Sopenharmony_ci  FILE *fp;
590141cc406Sopenharmony_ci
591141cc406Sopenharmony_ci  DBG_INIT ();
592141cc406Sopenharmony_ci
593141cc406Sopenharmony_ci  DBG (2, "sane_init: version_code %s 0, authorize %s 0\n",
594141cc406Sopenharmony_ci       version_code == 0 ? "=" : "!=", authorize == 0 ? "=" : "!=");
595141cc406Sopenharmony_ci  DBG (1, "sane_init: SANE umax1220u backend version %d.%d.%d from %s\n",
596141cc406Sopenharmony_ci       SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD, PACKAGE_STRING);
597141cc406Sopenharmony_ci
598141cc406Sopenharmony_ci  if (version_code)
599141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
600141cc406Sopenharmony_ci
601141cc406Sopenharmony_ci  sanei_usb_init ();
602141cc406Sopenharmony_ci  sanei_pv8630_init ();
603141cc406Sopenharmony_ci
604141cc406Sopenharmony_ci  fp = sanei_config_open (UMAX_CONFIG_FILE);
605141cc406Sopenharmony_ci  if (!fp)
606141cc406Sopenharmony_ci    {
607141cc406Sopenharmony_ci      /* no config-file: try /dev/scanner and /dev/usbscanner. */
608141cc406Sopenharmony_ci      attach_scanner ("/dev/scanner", 0);
609141cc406Sopenharmony_ci      attach_scanner ("/dev/usbscanner", 0);
610141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
611141cc406Sopenharmony_ci    }
612141cc406Sopenharmony_ci
613141cc406Sopenharmony_ci  DBG (3, "reading configure file %s\n", UMAX_CONFIG_FILE);
614141cc406Sopenharmony_ci
615141cc406Sopenharmony_ci  while (sanei_config_read (config_line, sizeof (config_line), fp))
616141cc406Sopenharmony_ci    {
617141cc406Sopenharmony_ci      if (config_line[0] == '#')
618141cc406Sopenharmony_ci        continue;                /* ignore line comments */
619141cc406Sopenharmony_ci
620141cc406Sopenharmony_ci      len = strlen (config_line);
621141cc406Sopenharmony_ci
622141cc406Sopenharmony_ci      if (!len)
623141cc406Sopenharmony_ci        continue;                /* ignore empty lines */
624141cc406Sopenharmony_ci
625141cc406Sopenharmony_ci      DBG (4, "attach_matching_devices(%s)\n", config_line);
626141cc406Sopenharmony_ci      sanei_usb_attach_matching_devices (config_line, attach_one);
627141cc406Sopenharmony_ci    }
628141cc406Sopenharmony_ci
629141cc406Sopenharmony_ci  DBG (4, "finished reading configure file\n");
630141cc406Sopenharmony_ci
631141cc406Sopenharmony_ci  fclose (fp);
632141cc406Sopenharmony_ci
633141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
634141cc406Sopenharmony_ci}
635141cc406Sopenharmony_ci
636141cc406Sopenharmony_civoid
637141cc406Sopenharmony_cisane_exit (void)
638141cc406Sopenharmony_ci{
639141cc406Sopenharmony_ci  Umax_Device *dev, *next;
640141cc406Sopenharmony_ci
641141cc406Sopenharmony_ci  DBG (3, "sane_exit\n");
642141cc406Sopenharmony_ci
643141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = next)
644141cc406Sopenharmony_ci    {
645141cc406Sopenharmony_ci      next = dev->next;
646141cc406Sopenharmony_ci      free (dev->name);
647141cc406Sopenharmony_ci      free (dev);
648141cc406Sopenharmony_ci    }
649141cc406Sopenharmony_ci
650141cc406Sopenharmony_ci  if (devlist)
651141cc406Sopenharmony_ci    free (devlist);
652141cc406Sopenharmony_ci  return;
653141cc406Sopenharmony_ci}
654141cc406Sopenharmony_ci
655141cc406Sopenharmony_ciSANE_Status
656141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
657141cc406Sopenharmony_ci{
658141cc406Sopenharmony_ci  Umax_Device *dev;
659141cc406Sopenharmony_ci  int i;
660141cc406Sopenharmony_ci
661141cc406Sopenharmony_ci  DBG (3, "sane_get_devices(local_only = %d)\n", local_only);
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci  if (devlist)
664141cc406Sopenharmony_ci    free (devlist);
665141cc406Sopenharmony_ci
666141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
667141cc406Sopenharmony_ci  if (!devlist)
668141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
669141cc406Sopenharmony_ci
670141cc406Sopenharmony_ci  i = 0;
671141cc406Sopenharmony_ci
672141cc406Sopenharmony_ci  for (dev = first_dev; i < num_devices; dev = dev->next)
673141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
674141cc406Sopenharmony_ci
675141cc406Sopenharmony_ci  devlist[i++] = 0;
676141cc406Sopenharmony_ci
677141cc406Sopenharmony_ci  *device_list = devlist;
678141cc406Sopenharmony_ci
679141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
680141cc406Sopenharmony_ci}
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ciSANE_Status
683141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
684141cc406Sopenharmony_ci{
685141cc406Sopenharmony_ci  Umax_Device *dev;
686141cc406Sopenharmony_ci  SANE_Status status;
687141cc406Sopenharmony_ci  Umax_Scanner *scanner;
688141cc406Sopenharmony_ci
689141cc406Sopenharmony_ci  DBG (3, "sane_open\n");
690141cc406Sopenharmony_ci
691141cc406Sopenharmony_ci  if (devicename[0])                /* search for devicename */
692141cc406Sopenharmony_ci    {
693141cc406Sopenharmony_ci      DBG (4, "sane_open: devicename=%s\n", devicename);
694141cc406Sopenharmony_ci
695141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
696141cc406Sopenharmony_ci          if (strcmp (dev->sane.name, devicename) == 0)
697141cc406Sopenharmony_ci            break;
698141cc406Sopenharmony_ci
699141cc406Sopenharmony_ci      if (!dev)
700141cc406Sopenharmony_ci        {
701141cc406Sopenharmony_ci          status = attach_scanner (devicename, &dev);
702141cc406Sopenharmony_ci          if (status != SANE_STATUS_GOOD)
703141cc406Sopenharmony_ci            return status;
704141cc406Sopenharmony_ci        }
705141cc406Sopenharmony_ci    }
706141cc406Sopenharmony_ci  else
707141cc406Sopenharmony_ci    {
708141cc406Sopenharmony_ci      DBG (2, "sane_open: no devicename, opening first device\n");
709141cc406Sopenharmony_ci      dev = first_dev;
710141cc406Sopenharmony_ci    }
711141cc406Sopenharmony_ci
712141cc406Sopenharmony_ci  if (!dev)
713141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
714141cc406Sopenharmony_ci
715141cc406Sopenharmony_ci  scanner = malloc (sizeof (*scanner));
716141cc406Sopenharmony_ci  if (!scanner)
717141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
718141cc406Sopenharmony_ci
719141cc406Sopenharmony_ci  memset (scanner, 0, sizeof (*scanner));
720141cc406Sopenharmony_ci  scanner->device = dev;
721141cc406Sopenharmony_ci
722141cc406Sopenharmony_ci  status = UMAX_open_device (&scanner->scan, dev->sane.name);
723141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
724141cc406Sopenharmony_ci    {
725141cc406Sopenharmony_ci      free (scanner);
726141cc406Sopenharmony_ci      return status;
727141cc406Sopenharmony_ci    }
728141cc406Sopenharmony_ci
729141cc406Sopenharmony_ci  *handle = scanner;
730141cc406Sopenharmony_ci
731141cc406Sopenharmony_ci  /* insert newly opened handle into list of open handles: */
732141cc406Sopenharmony_ci  scanner->next = first_handle;
733141cc406Sopenharmony_ci
734141cc406Sopenharmony_ci  first_handle = scanner;
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
737141cc406Sopenharmony_ci}
738141cc406Sopenharmony_ci
739141cc406Sopenharmony_civoid
740141cc406Sopenharmony_cisane_close (SANE_Handle handle)
741141cc406Sopenharmony_ci{
742141cc406Sopenharmony_ci  Umax_Scanner *prev, *scanner;
743141cc406Sopenharmony_ci
744141cc406Sopenharmony_ci  DBG (3, "sane_close\n");
745141cc406Sopenharmony_ci
746141cc406Sopenharmony_ci  if (!first_handle)
747141cc406Sopenharmony_ci    {
748141cc406Sopenharmony_ci      DBG (1, "ERROR: sane_close: no handles opened\n");
749141cc406Sopenharmony_ci      return;
750141cc406Sopenharmony_ci    }
751141cc406Sopenharmony_ci
752141cc406Sopenharmony_ci  /* remove handle from list of open handles: */
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_ci  prev = NULL;
755141cc406Sopenharmony_ci
756141cc406Sopenharmony_ci  for (scanner = first_handle; scanner; scanner = scanner->next)
757141cc406Sopenharmony_ci    {
758141cc406Sopenharmony_ci      if (scanner == handle)
759141cc406Sopenharmony_ci        break;
760141cc406Sopenharmony_ci
761141cc406Sopenharmony_ci      prev = scanner;
762141cc406Sopenharmony_ci    }
763141cc406Sopenharmony_ci
764141cc406Sopenharmony_ci  if (!scanner)
765141cc406Sopenharmony_ci    {
766141cc406Sopenharmony_ci      DBG (1, "ERROR: sane_close: invalid handle %p\n", handle);
767141cc406Sopenharmony_ci      return;                        /* oops, not a handle we know about */
768141cc406Sopenharmony_ci    }
769141cc406Sopenharmony_ci
770141cc406Sopenharmony_ci  if (prev)
771141cc406Sopenharmony_ci    prev->next = scanner->next;
772141cc406Sopenharmony_ci  else
773141cc406Sopenharmony_ci    first_handle = scanner->next;
774141cc406Sopenharmony_ci
775141cc406Sopenharmony_ci  UMAX_close_device (&scanner->scan);
776141cc406Sopenharmony_ci
777141cc406Sopenharmony_ci  free (scanner);
778141cc406Sopenharmony_ci}
779141cc406Sopenharmony_ci
780141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
781141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
782141cc406Sopenharmony_ci{
783141cc406Sopenharmony_ci  (void) handle;                /* Eliminate compiler warning */
784141cc406Sopenharmony_ci
785141cc406Sopenharmony_ci  DBG (3, "sane_get_option_descriptor: option = %d\n", option);
786141cc406Sopenharmony_ci  if (option < 0 || option >= NELEMS (so))
787141cc406Sopenharmony_ci    return NULL;
788141cc406Sopenharmony_ci  return so[option].descriptor;
789141cc406Sopenharmony_ci}
790141cc406Sopenharmony_ci
791141cc406Sopenharmony_ciSANE_Status
792141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
793141cc406Sopenharmony_ci                     SANE_Action action, void *value, SANE_Int * info)
794141cc406Sopenharmony_ci{
795141cc406Sopenharmony_ci  (void) handle;                /* Eliminate compiler warning */
796141cc406Sopenharmony_ci
797141cc406Sopenharmony_ci  DBG (3,
798141cc406Sopenharmony_ci       "sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n",
799141cc406Sopenharmony_ci       handle, option, action, value, (void*) info);
800141cc406Sopenharmony_ci
801141cc406Sopenharmony_ci  return dispatch_control_option (handle, option, action, value, info);
802141cc406Sopenharmony_ci}
803141cc406Sopenharmony_ci
804141cc406Sopenharmony_ciSANE_Status
805141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
806141cc406Sopenharmony_ci{
807141cc406Sopenharmony_ci  int rc = SANE_STATUS_GOOD;
808141cc406Sopenharmony_ci  int w =
809141cc406Sopenharmony_ci    SANE_UNFIX (optionBotRightXValue -
810141cc406Sopenharmony_ci                optionTopLeftXValue) / MM_IN_INCH * optionResolutionValue;
811141cc406Sopenharmony_ci  int h =
812141cc406Sopenharmony_ci    SANE_UNFIX (optionBotRightYValue -
813141cc406Sopenharmony_ci                optionTopLeftYValue) / MM_IN_INCH * optionResolutionValue;
814141cc406Sopenharmony_ci
815141cc406Sopenharmony_ci  (void) handle;                /* Eliminate compiler warning */
816141cc406Sopenharmony_ci
817141cc406Sopenharmony_ci  DBG (3, "sane_get_parameters\n");
818141cc406Sopenharmony_ci  parms.depth = 8;
819141cc406Sopenharmony_ci  parms.last_frame = SANE_TRUE;
820141cc406Sopenharmony_ci  parms.pixels_per_line = w;
821141cc406Sopenharmony_ci  parms.lines = h;
822141cc406Sopenharmony_ci
823141cc406Sopenharmony_ci  if (optionGrayscaleValue == SANE_TRUE)
824141cc406Sopenharmony_ci    {
825141cc406Sopenharmony_ci      parms.format = SANE_FRAME_GRAY;
826141cc406Sopenharmony_ci      parms.bytes_per_line = w;
827141cc406Sopenharmony_ci    }
828141cc406Sopenharmony_ci  else
829141cc406Sopenharmony_ci    {
830141cc406Sopenharmony_ci      parms.format = SANE_FRAME_RGB;
831141cc406Sopenharmony_ci      parms.bytes_per_line = w * 3;
832141cc406Sopenharmony_ci    }
833141cc406Sopenharmony_ci  *params = parms;
834141cc406Sopenharmony_ci  return rc;
835141cc406Sopenharmony_ci}
836141cc406Sopenharmony_ci
837141cc406Sopenharmony_ciSANE_Status
838141cc406Sopenharmony_cisane_start (SANE_Handle handle)
839141cc406Sopenharmony_ci{
840141cc406Sopenharmony_ci  Umax_Scanner *scanner = handle;
841141cc406Sopenharmony_ci  SANE_Status res;
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci  DBG (3, "sane_start\n");
844141cc406Sopenharmony_ci
845141cc406Sopenharmony_ci  res = UMAX_set_scan_parameters (&scanner->scan,
846141cc406Sopenharmony_ci                                  optionGrayscaleValue == SANE_FALSE,
847141cc406Sopenharmony_ci                                  SANE_UNFIX (optionTopLeftXValue) /
848141cc406Sopenharmony_ci                                  MM_IN_INCH * 600,
849141cc406Sopenharmony_ci                                  SANE_UNFIX (optionTopLeftYValue) /
850141cc406Sopenharmony_ci                                  MM_IN_INCH * 600,
851141cc406Sopenharmony_ci                                  SANE_UNFIX (optionBotRightXValue -
852141cc406Sopenharmony_ci                                              optionTopLeftXValue) /
853141cc406Sopenharmony_ci                                  MM_IN_INCH * optionResolutionValue,
854141cc406Sopenharmony_ci                                  SANE_UNFIX (optionBotRightYValue -
855141cc406Sopenharmony_ci                                              optionTopLeftYValue) /
856141cc406Sopenharmony_ci                                  MM_IN_INCH * optionResolutionValue,
857141cc406Sopenharmony_ci                                  optionResolutionValue,
858141cc406Sopenharmony_ci                                  optionResolutionValue);
859141cc406Sopenharmony_ci
860141cc406Sopenharmony_ci  if (res != SANE_STATUS_GOOD)
861141cc406Sopenharmony_ci    return res;
862141cc406Sopenharmony_ci
863141cc406Sopenharmony_ci  if (scanner->scan.model == ASTRA_1220U)
864141cc406Sopenharmony_ci     return UMAX_start_scan (&scanner->scan);
865141cc406Sopenharmony_ci  else
866141cc406Sopenharmony_ci     return UMAX_start_scan_2100U (&scanner->scan);
867141cc406Sopenharmony_ci}
868141cc406Sopenharmony_ci
869141cc406Sopenharmony_ciSANE_Status
870141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * data,
871141cc406Sopenharmony_ci           SANE_Int max_length, SANE_Int * length)
872141cc406Sopenharmony_ci{
873141cc406Sopenharmony_ci  Umax_Scanner *scanner = handle;
874141cc406Sopenharmony_ci  SANE_Status res;
875141cc406Sopenharmony_ci  int len;
876141cc406Sopenharmony_ci  unsigned char rgb[3];
877141cc406Sopenharmony_ci
878141cc406Sopenharmony_ci  len = *length = 0;
879141cc406Sopenharmony_ci
880141cc406Sopenharmony_ci  if (!data || !length)
881141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
882141cc406Sopenharmony_ci
883141cc406Sopenharmony_ci  if (scanner->scan.done)
884141cc406Sopenharmony_ci    {
885141cc406Sopenharmony_ci      res = UMAX_finish_scan (&scanner->scan);
886141cc406Sopenharmony_ci
887141cc406Sopenharmony_ci      if (scanner->scan.model == ASTRA_1220U)
888141cc406Sopenharmony_ci        res = UMAX_park_head (&scanner->scan);
889141cc406Sopenharmony_ci      else
890141cc406Sopenharmony_ci        res = UMAX_park_head_2100U (&scanner->scan);
891141cc406Sopenharmony_ci
892141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
893141cc406Sopenharmony_ci    }
894141cc406Sopenharmony_ci
895141cc406Sopenharmony_ci  DBG (3, "sane_read: max_length = %d\n", max_length);
896141cc406Sopenharmony_ci
897141cc406Sopenharmony_ci  if (optionGrayscaleValue == SANE_FALSE)
898141cc406Sopenharmony_ci    {
899141cc406Sopenharmony_ci      while (!scanner->scan.done && (max_length >= 3))
900141cc406Sopenharmony_ci        {
901141cc406Sopenharmony_ci          res = UMAX_get_rgb (&scanner->scan, rgb);
902141cc406Sopenharmony_ci          if (res != SANE_STATUS_GOOD)
903141cc406Sopenharmony_ci            {
904141cc406Sopenharmony_ci              *length = 0;
905141cc406Sopenharmony_ci              return res;
906141cc406Sopenharmony_ci            }
907141cc406Sopenharmony_ci          *data++ = rgb[0];
908141cc406Sopenharmony_ci          *data++ = rgb[1];
909141cc406Sopenharmony_ci          *data++ = rgb[2];
910141cc406Sopenharmony_ci          max_length -= 3;
911141cc406Sopenharmony_ci          len += 3;
912141cc406Sopenharmony_ci        }
913141cc406Sopenharmony_ci    }
914141cc406Sopenharmony_ci  else
915141cc406Sopenharmony_ci    {
916141cc406Sopenharmony_ci      while (!scanner->scan.done && max_length)
917141cc406Sopenharmony_ci        {
918141cc406Sopenharmony_ci          res = UMAX_get_rgb (&scanner->scan, rgb);
919141cc406Sopenharmony_ci          if (res != SANE_STATUS_GOOD)
920141cc406Sopenharmony_ci            {
921141cc406Sopenharmony_ci              *length = 0;
922141cc406Sopenharmony_ci              return res;
923141cc406Sopenharmony_ci            }
924141cc406Sopenharmony_ci          *data++ = rgb[0];
925141cc406Sopenharmony_ci          max_length--;
926141cc406Sopenharmony_ci          len++;
927141cc406Sopenharmony_ci        }
928141cc406Sopenharmony_ci    }
929141cc406Sopenharmony_ci
930141cc406Sopenharmony_ci  *length = len;
931141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
932141cc406Sopenharmony_ci}
933141cc406Sopenharmony_ci
934141cc406Sopenharmony_civoid
935141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
936141cc406Sopenharmony_ci{
937141cc406Sopenharmony_ci  DBG (3, "sane_cancel: handle = %p\n", handle);
938141cc406Sopenharmony_ci  DBG (3, "sane_cancel: canceling is unsupported in this backend\n");
939141cc406Sopenharmony_ci}
940141cc406Sopenharmony_ci
941141cc406Sopenharmony_ciSANE_Status
942141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
943141cc406Sopenharmony_ci{
944141cc406Sopenharmony_ci  DBG (3, "sane_set_io_mode: handle = %p, non_blocking = %d\n", handle,
945141cc406Sopenharmony_ci       non_blocking);
946141cc406Sopenharmony_ci  if (non_blocking != SANE_FALSE)
947141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
948141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
949141cc406Sopenharmony_ci}
950141cc406Sopenharmony_ci
951141cc406Sopenharmony_ciSANE_Status
952141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
953141cc406Sopenharmony_ci{
954141cc406Sopenharmony_ci  DBG (3, "sane_get_select_fd: handle = %p, fd %s 0\n", handle,
955141cc406Sopenharmony_ci       fd ? "!=" : "=");
956141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
957141cc406Sopenharmony_ci}
958