1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2000 Mustek.
4141cc406Sopenharmony_ci   Originally maintained by Tom Wang <tom.wang@mustek.com.tw>
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   Copyright (C) 2001 - 2004 by Henning Meier-Geinitz.
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci   This file is part of the SANE package.
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   This file implements a SANE backend for Mustek 1200UB and similar
45141cc406Sopenharmony_ci   USB flatbed scanners.  */
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci#define BUILD 18
48141cc406Sopenharmony_ci
49141cc406Sopenharmony_ci#include "../include/sane/config.h"
50141cc406Sopenharmony_ci
51141cc406Sopenharmony_ci#include <ctype.h>
52141cc406Sopenharmony_ci#include <errno.h>
53141cc406Sopenharmony_ci#include <fcntl.h>
54141cc406Sopenharmony_ci#include <limits.h>
55141cc406Sopenharmony_ci#include <signal.h>
56141cc406Sopenharmony_ci#include <stdio.h>
57141cc406Sopenharmony_ci#include <stdlib.h>
58141cc406Sopenharmony_ci#include <string.h>
59141cc406Sopenharmony_ci#include <unistd.h>
60141cc406Sopenharmony_ci
61141cc406Sopenharmony_ci#include <sys/time.h>
62141cc406Sopenharmony_ci#include <sys/types.h>
63141cc406Sopenharmony_ci#include <sys/wait.h>
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci#include "../include/sane/sane.h"
66141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
67141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
68141cc406Sopenharmony_ci
69141cc406Sopenharmony_ci#define BACKEND_NAME mustek_usb
70141cc406Sopenharmony_ci
71141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
72141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
73141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ci#include "mustek_usb.h"
76141cc406Sopenharmony_ci#include "mustek_usb_high.c"
77141cc406Sopenharmony_ci
78141cc406Sopenharmony_ci#ifndef SANE_I18N
79141cc406Sopenharmony_ci#define SANE_I18N(text) text
80141cc406Sopenharmony_ci#endif
81141cc406Sopenharmony_ci
82141cc406Sopenharmony_cistatic SANE_Int num_devices;
83141cc406Sopenharmony_cistatic Mustek_Usb_Device *first_dev;
84141cc406Sopenharmony_cistatic Mustek_Usb_Scanner *first_handle;
85141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_ci/* Maximum amount of data read in one turn from USB. */
88141cc406Sopenharmony_cistatic SANE_Word max_block_size = (8 * 1024);
89141cc406Sopenharmony_ci
90141cc406Sopenharmony_ci/* Array of newly attached devices */
91141cc406Sopenharmony_cistatic Mustek_Usb_Device **new_dev;
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_ci/* Length of new_dev array */
94141cc406Sopenharmony_cistatic SANE_Int new_dev_len;
95141cc406Sopenharmony_ci
96141cc406Sopenharmony_ci/* Number of entries allocated for new_dev */
97141cc406Sopenharmony_cistatic SANE_Int new_dev_alloced;
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_cistatic SANE_String_Const mode_list[6];
100141cc406Sopenharmony_ci
101141cc406Sopenharmony_cistatic const SANE_Range u8_range = {
102141cc406Sopenharmony_ci  0,				/* minimum */
103141cc406Sopenharmony_ci  255,				/* maximum */
104141cc406Sopenharmony_ci  0				/* quantization */
105141cc406Sopenharmony_ci};
106141cc406Sopenharmony_ci
107141cc406Sopenharmony_ci
108141cc406Sopenharmony_cistatic size_t
109141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
110141cc406Sopenharmony_ci{
111141cc406Sopenharmony_ci  size_t size, max_size = 0;
112141cc406Sopenharmony_ci  SANE_Int i;
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
115141cc406Sopenharmony_ci    {
116141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
117141cc406Sopenharmony_ci      if (size > max_size)
118141cc406Sopenharmony_ci	max_size = size;
119141cc406Sopenharmony_ci    }
120141cc406Sopenharmony_ci  return max_size;
121141cc406Sopenharmony_ci}
122141cc406Sopenharmony_ci
123141cc406Sopenharmony_ci
124141cc406Sopenharmony_cistatic SANE_Status
125141cc406Sopenharmony_cicalc_parameters (Mustek_Usb_Scanner * s)
126141cc406Sopenharmony_ci{
127141cc406Sopenharmony_ci  SANE_String val;
128141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
129141cc406Sopenharmony_ci  SANE_Int max_x, max_y;
130141cc406Sopenharmony_ci
131141cc406Sopenharmony_ci  DBG (5, "calc_parameters: start\n");
132141cc406Sopenharmony_ci  val = s->val[OPT_MODE].s;
133141cc406Sopenharmony_ci
134141cc406Sopenharmony_ci  s->params.last_frame = SANE_TRUE;
135141cc406Sopenharmony_ci
136141cc406Sopenharmony_ci  if (!strcmp (val, SANE_VALUE_SCAN_MODE_LINEART))
137141cc406Sopenharmony_ci    {
138141cc406Sopenharmony_ci      s->params.format = SANE_FRAME_GRAY;
139141cc406Sopenharmony_ci      s->params.depth = 1;
140141cc406Sopenharmony_ci      s->bpp = 1;
141141cc406Sopenharmony_ci      s->channels = 1;
142141cc406Sopenharmony_ci    }
143141cc406Sopenharmony_ci  else if (!strcmp (val, SANE_VALUE_SCAN_MODE_GRAY))
144141cc406Sopenharmony_ci    {
145141cc406Sopenharmony_ci      s->params.format = SANE_FRAME_GRAY;
146141cc406Sopenharmony_ci      s->params.depth = 8;
147141cc406Sopenharmony_ci      s->bpp = 8;
148141cc406Sopenharmony_ci      s->channels = 1;
149141cc406Sopenharmony_ci    }
150141cc406Sopenharmony_ci  else if (!strcmp (val, SANE_VALUE_SCAN_MODE_COLOR))
151141cc406Sopenharmony_ci    {
152141cc406Sopenharmony_ci      s->params.format = SANE_FRAME_RGB;
153141cc406Sopenharmony_ci      s->params.depth = 8;
154141cc406Sopenharmony_ci      s->bpp = 24;
155141cc406Sopenharmony_ci      s->channels = 3;
156141cc406Sopenharmony_ci    }
157141cc406Sopenharmony_ci  else
158141cc406Sopenharmony_ci    {
159141cc406Sopenharmony_ci      DBG (1, "calc_parameters: invalid mode %s\n", (SANE_Char *) val);
160141cc406Sopenharmony_ci      status = SANE_STATUS_INVAL;
161141cc406Sopenharmony_ci    }
162141cc406Sopenharmony_ci
163141cc406Sopenharmony_ci  s->tl_x = SANE_UNFIX (s->val[OPT_TL_X].w) / MM_PER_INCH;
164141cc406Sopenharmony_ci  s->tl_y = SANE_UNFIX (s->val[OPT_TL_Y].w) / MM_PER_INCH;
165141cc406Sopenharmony_ci  s->width = SANE_UNFIX (s->val[OPT_BR_X].w) / MM_PER_INCH - s->tl_x;
166141cc406Sopenharmony_ci  s->height = SANE_UNFIX (s->val[OPT_BR_Y].w) / MM_PER_INCH - s->tl_y;
167141cc406Sopenharmony_ci
168141cc406Sopenharmony_ci  if (s->width < 0)
169141cc406Sopenharmony_ci    {
170141cc406Sopenharmony_ci      DBG (1, "calc_parameters: warning: tl_x > br_x\n");
171141cc406Sopenharmony_ci    }
172141cc406Sopenharmony_ci  if (s->height < 0)
173141cc406Sopenharmony_ci    {
174141cc406Sopenharmony_ci      DBG (1, "calc_parameters: warning: tl_y > br_y\n");
175141cc406Sopenharmony_ci    }
176141cc406Sopenharmony_ci  max_x = s->hw->max_width * SANE_UNFIX (s->val[OPT_RESOLUTION].w) / 300;
177141cc406Sopenharmony_ci  max_y = s->hw->max_height * SANE_UNFIX (s->val[OPT_RESOLUTION].w) / 300;
178141cc406Sopenharmony_ci
179141cc406Sopenharmony_ci  s->tl_x_dots = s->tl_x * SANE_UNFIX (s->val[OPT_RESOLUTION].w);
180141cc406Sopenharmony_ci  s->width_dots = s->width * SANE_UNFIX (s->val[OPT_RESOLUTION].w);
181141cc406Sopenharmony_ci  s->tl_y_dots = s->tl_y * SANE_UNFIX (s->val[OPT_RESOLUTION].w);
182141cc406Sopenharmony_ci  s->height_dots = s->height * SANE_UNFIX (s->val[OPT_RESOLUTION].w);
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_ci  if (s->width_dots > max_x)
185141cc406Sopenharmony_ci    s->width_dots = max_x;
186141cc406Sopenharmony_ci  if (s->height_dots > max_y)
187141cc406Sopenharmony_ci    s->height_dots = max_y;
188141cc406Sopenharmony_ci  if (!strcmp (val, SANE_VALUE_SCAN_MODE_LINEART))
189141cc406Sopenharmony_ci    {
190141cc406Sopenharmony_ci      s->width_dots = (s->width_dots / 8) * 8;
191141cc406Sopenharmony_ci      if (s->width_dots == 0)
192141cc406Sopenharmony_ci	s->width_dots = 8;
193141cc406Sopenharmony_ci    }
194141cc406Sopenharmony_ci  if (s->tl_x_dots < 0)
195141cc406Sopenharmony_ci    s->tl_x_dots = 0;
196141cc406Sopenharmony_ci  if (s->tl_y_dots < 0)
197141cc406Sopenharmony_ci    s->tl_y_dots = 0;
198141cc406Sopenharmony_ci  if (s->tl_x_dots + s->width_dots > max_x)
199141cc406Sopenharmony_ci    s->tl_x_dots = max_x - s->width_dots;
200141cc406Sopenharmony_ci  if (s->tl_y_dots + s->height_dots > max_y)
201141cc406Sopenharmony_ci    s->tl_y_dots = max_y - s->height_dots;
202141cc406Sopenharmony_ci
203141cc406Sopenharmony_ci  s->val[OPT_TL_X].w = SANE_FIX (s->tl_x * MM_PER_INCH);
204141cc406Sopenharmony_ci  s->val[OPT_TL_Y].w = SANE_FIX (s->tl_y * MM_PER_INCH);
205141cc406Sopenharmony_ci  s->val[OPT_BR_X].w = SANE_FIX ((s->tl_x + s->width) * MM_PER_INCH);
206141cc406Sopenharmony_ci  s->val[OPT_BR_Y].w = SANE_FIX ((s->tl_y + s->height) * MM_PER_INCH);
207141cc406Sopenharmony_ci
208141cc406Sopenharmony_ci  s->params.pixels_per_line = s->width_dots;
209141cc406Sopenharmony_ci  if (s->params.pixels_per_line < 0)
210141cc406Sopenharmony_ci    s->params.pixels_per_line = 0;
211141cc406Sopenharmony_ci  s->params.lines = s->height_dots;
212141cc406Sopenharmony_ci  if (s->params.lines < 0)
213141cc406Sopenharmony_ci    s->params.lines = 0;
214141cc406Sopenharmony_ci  s->params.bytes_per_line = s->params.pixels_per_line * s->params.depth / 8
215141cc406Sopenharmony_ci    * s->channels;
216141cc406Sopenharmony_ci
217141cc406Sopenharmony_ci  DBG (4, "calc_parameters: format=%d\n", s->params.format);
218141cc406Sopenharmony_ci  DBG (4, "calc_parameters: last frame=%d\n", s->params.last_frame);
219141cc406Sopenharmony_ci  DBG (4, "calc_parameters: lines=%d\n", s->params.lines);
220141cc406Sopenharmony_ci  DBG (4, "calc_parameters: pixels per line=%d\n", s->params.pixels_per_line);
221141cc406Sopenharmony_ci  DBG (4, "calc_parameters: bytes per line=%d\n", s->params.bytes_per_line);
222141cc406Sopenharmony_ci  DBG (4, "calc_parameters: Pixels %dx%dx%d\n",
223141cc406Sopenharmony_ci       s->params.pixels_per_line, s->params.lines, 1 << s->params.depth);
224141cc406Sopenharmony_ci
225141cc406Sopenharmony_ci  DBG (5, "calc_parameters: exit\n");
226141cc406Sopenharmony_ci  return status;
227141cc406Sopenharmony_ci}
228141cc406Sopenharmony_ci
229141cc406Sopenharmony_ci
230141cc406Sopenharmony_cistatic SANE_Status
231141cc406Sopenharmony_ciinit_options (Mustek_Usb_Scanner * s)
232141cc406Sopenharmony_ci{
233141cc406Sopenharmony_ci  SANE_Int option;
234141cc406Sopenharmony_ci  SANE_Status status;
235141cc406Sopenharmony_ci
236141cc406Sopenharmony_ci  DBG (5, "init_options: start\n");
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_ci  memset (s->opt, 0, sizeof (s->opt));
239141cc406Sopenharmony_ci  memset (s->val, 0, sizeof (s->val));
240141cc406Sopenharmony_ci
241141cc406Sopenharmony_ci  for (option = 0; option < NUM_OPTIONS; ++option)
242141cc406Sopenharmony_ci    {
243141cc406Sopenharmony_ci      s->opt[option].size = sizeof (SANE_Word);
244141cc406Sopenharmony_ci      s->opt[option].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
245141cc406Sopenharmony_ci    }
246141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
247141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
248141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
249141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
250141cc406Sopenharmony_ci  s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
251141cc406Sopenharmony_ci  s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
252141cc406Sopenharmony_ci
253141cc406Sopenharmony_ci  /* "Mode" group: */
254141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode");
255141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].desc = "";
256141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
257141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].size = 0;
258141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].cap = 0;
259141cc406Sopenharmony_ci  s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_ci  /* scan mode */
262141cc406Sopenharmony_ci  mode_list[0] = SANE_VALUE_SCAN_MODE_COLOR;
263141cc406Sopenharmony_ci  mode_list[1] = SANE_VALUE_SCAN_MODE_GRAY;
264141cc406Sopenharmony_ci  mode_list[2] = SANE_VALUE_SCAN_MODE_LINEART;
265141cc406Sopenharmony_ci  mode_list[3] = NULL;
266141cc406Sopenharmony_ci
267141cc406Sopenharmony_ci  s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
268141cc406Sopenharmony_ci  s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
269141cc406Sopenharmony_ci  s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
270141cc406Sopenharmony_ci  s->opt[OPT_MODE].type = SANE_TYPE_STRING;
271141cc406Sopenharmony_ci  s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
272141cc406Sopenharmony_ci  s->opt[OPT_MODE].size = max_string_size (mode_list);
273141cc406Sopenharmony_ci  s->opt[OPT_MODE].constraint.string_list = mode_list;
274141cc406Sopenharmony_ci  s->val[OPT_MODE].s = strdup (mode_list[1]);
275141cc406Sopenharmony_ci
276141cc406Sopenharmony_ci  /* resolution */
277141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
278141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
279141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
280141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].type = SANE_TYPE_FIXED;
281141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
282141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
283141cc406Sopenharmony_ci  s->opt[OPT_RESOLUTION].constraint.range = &s->hw->dpi_range;
284141cc406Sopenharmony_ci  s->val[OPT_RESOLUTION].w = s->hw->dpi_range.min;
285141cc406Sopenharmony_ci  if (s->hw->chip->scanner_type == MT_600CU)
286141cc406Sopenharmony_ci    s->hw->dpi_range.max = SANE_FIX (600);
287141cc406Sopenharmony_ci  else
288141cc406Sopenharmony_ci    s->hw->dpi_range.max = SANE_FIX (1200);
289141cc406Sopenharmony_ci
290141cc406Sopenharmony_ci  /* preview */
291141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
292141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
293141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
294141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
295141cc406Sopenharmony_ci  s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
296141cc406Sopenharmony_ci  s->val[OPT_PREVIEW].w = SANE_FALSE;
297141cc406Sopenharmony_ci
298141cc406Sopenharmony_ci  /* "Geometry" group: */
299141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry");
300141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].desc = "";
301141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
302141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
303141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].size = 0;
304141cc406Sopenharmony_ci  s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_ci  /* top-left x */
307141cc406Sopenharmony_ci  s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
308141cc406Sopenharmony_ci  s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
309141cc406Sopenharmony_ci  s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
310141cc406Sopenharmony_ci  s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
311141cc406Sopenharmony_ci  s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
312141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
313141cc406Sopenharmony_ci  s->opt[OPT_TL_X].constraint.range = &s->hw->x_range;
314141cc406Sopenharmony_ci  s->val[OPT_TL_X].w = 0;
315141cc406Sopenharmony_ci
316141cc406Sopenharmony_ci  /* top-left y */
317141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
318141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
319141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
320141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
321141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
322141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
323141cc406Sopenharmony_ci  s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range;
324141cc406Sopenharmony_ci  s->val[OPT_TL_Y].w = 0;
325141cc406Sopenharmony_ci
326141cc406Sopenharmony_ci  /* bottom-right x */
327141cc406Sopenharmony_ci  s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
328141cc406Sopenharmony_ci  s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
329141cc406Sopenharmony_ci  s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
330141cc406Sopenharmony_ci  s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
331141cc406Sopenharmony_ci  s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
332141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
333141cc406Sopenharmony_ci  s->opt[OPT_BR_X].constraint.range = &s->hw->x_range;
334141cc406Sopenharmony_ci  s->val[OPT_BR_X].w = s->hw->x_range.max;
335141cc406Sopenharmony_ci
336141cc406Sopenharmony_ci  /* bottom-right y */
337141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
338141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
339141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
340141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
341141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
342141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
343141cc406Sopenharmony_ci  s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range;
344141cc406Sopenharmony_ci  s->val[OPT_BR_Y].w = s->hw->y_range.max;
345141cc406Sopenharmony_ci
346141cc406Sopenharmony_ci  /* "Enhancement" group: */
347141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement");
348141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
349141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
350141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].size = 0;
351141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
352141cc406Sopenharmony_ci  s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
353141cc406Sopenharmony_ci
354141cc406Sopenharmony_ci  /* threshold */
355141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
356141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
357141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
358141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
359141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
360141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
361141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].constraint.range = &u8_range;
362141cc406Sopenharmony_ci  s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
363141cc406Sopenharmony_ci  s->val[OPT_THRESHOLD].w = 128;
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci  /* custom-gamma table */
366141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
367141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
368141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
369141cc406Sopenharmony_ci  s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
370141cc406Sopenharmony_ci  s->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
371141cc406Sopenharmony_ci
372141cc406Sopenharmony_ci  /* gray gamma vector */
373141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
374141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
375141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
376141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
377141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
378141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
379141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word);
380141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
381141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR].constraint.range = &u8_range;
382141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR].wa = &s->gray_gamma_table[0];
383141cc406Sopenharmony_ci
384141cc406Sopenharmony_ci  /* red gamma vector */
385141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
386141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
387141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
388141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
389141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
390141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
391141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word);
392141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
393141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range;
394141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_R].wa = &s->red_gamma_table[0];
395141cc406Sopenharmony_ci
396141cc406Sopenharmony_ci  /* green gamma vector */
397141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
398141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
399141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
400141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
401141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
402141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
403141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word);
404141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
405141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range;
406141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_G].wa = &s->green_gamma_table[0];
407141cc406Sopenharmony_ci
408141cc406Sopenharmony_ci  /* blue gamma vector */
409141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
410141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
411141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
412141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
413141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
414141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
415141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word);
416141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
417141cc406Sopenharmony_ci  s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range;
418141cc406Sopenharmony_ci  s->val[OPT_GAMMA_VECTOR_B].wa = &s->blue_gamma_table[0];
419141cc406Sopenharmony_ci
420141cc406Sopenharmony_ci  RIE (calc_parameters (s));
421141cc406Sopenharmony_ci
422141cc406Sopenharmony_ci  DBG (5, "init_options: exit\n");
423141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
424141cc406Sopenharmony_ci}
425141cc406Sopenharmony_ci
426141cc406Sopenharmony_ci
427141cc406Sopenharmony_cistatic SANE_Status
428141cc406Sopenharmony_ciattach (SANE_String_Const devname, Mustek_Usb_Device ** devp,
429141cc406Sopenharmony_ci	SANE_Bool may_wait)
430141cc406Sopenharmony_ci{
431141cc406Sopenharmony_ci  Mustek_Usb_Device *dev;
432141cc406Sopenharmony_ci  SANE_Status status;
433141cc406Sopenharmony_ci  Mustek_Type scanner_type;
434141cc406Sopenharmony_ci  SANE_Int fd;
435141cc406Sopenharmony_ci
436141cc406Sopenharmony_ci  DBG (5, "attach: start: devp %s NULL, may_wait = %d\n", devp ? "!=" : "==",
437141cc406Sopenharmony_ci       may_wait);
438141cc406Sopenharmony_ci  if (!devname)
439141cc406Sopenharmony_ci    {
440141cc406Sopenharmony_ci      DBG (1, "attach: devname == NULL\n");
441141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
442141cc406Sopenharmony_ci    }
443141cc406Sopenharmony_ci
444141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
445141cc406Sopenharmony_ci    if (strcmp (dev->sane.name, devname) == 0)
446141cc406Sopenharmony_ci      {
447141cc406Sopenharmony_ci	if (devp)
448141cc406Sopenharmony_ci	  *devp = dev;
449141cc406Sopenharmony_ci	DBG (4, "attach: device `%s' was already in device list\n", devname);
450141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
451141cc406Sopenharmony_ci      }
452141cc406Sopenharmony_ci
453141cc406Sopenharmony_ci  DBG (4, "attach: trying to open device `%s'\n", devname);
454141cc406Sopenharmony_ci  status = sanei_usb_open (devname, &fd);
455141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
456141cc406Sopenharmony_ci    {
457141cc406Sopenharmony_ci      DBG (3, "attach: couldn't open device `%s': %s\n", devname,
458141cc406Sopenharmony_ci	   sane_strstatus (status));
459141cc406Sopenharmony_ci      return status;
460141cc406Sopenharmony_ci    }
461141cc406Sopenharmony_ci  DBG (4, "attach: device `%s' successfully opened\n", devname);
462141cc406Sopenharmony_ci
463141cc406Sopenharmony_ci  /* try to identify model */
464141cc406Sopenharmony_ci  DBG (4, "attach: trying to identify device `%s'\n", devname);
465141cc406Sopenharmony_ci  status = usb_low_identify_scanner (fd, &scanner_type);
466141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
467141cc406Sopenharmony_ci    {
468141cc406Sopenharmony_ci      DBG (1, "attach: device `%s' doesn't look like a supported scanner\n",
469141cc406Sopenharmony_ci	   devname);
470141cc406Sopenharmony_ci      sanei_usb_close (fd);
471141cc406Sopenharmony_ci      return status;
472141cc406Sopenharmony_ci    }
473141cc406Sopenharmony_ci  sanei_usb_close (fd);
474141cc406Sopenharmony_ci  if (scanner_type == MT_UNKNOWN)
475141cc406Sopenharmony_ci    {
476141cc406Sopenharmony_ci      DBG (3, "attach: warning: couldn't identify device `%s', must set "
477141cc406Sopenharmony_ci	   "type manually\n", devname);
478141cc406Sopenharmony_ci    }
479141cc406Sopenharmony_ci
480141cc406Sopenharmony_ci  dev = malloc (sizeof (Mustek_Usb_Device));
481141cc406Sopenharmony_ci  if (!dev)
482141cc406Sopenharmony_ci    {
483141cc406Sopenharmony_ci      DBG (1, "attach: couldn't malloc Mustek_Usb_Device\n");
484141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
485141cc406Sopenharmony_ci    }
486141cc406Sopenharmony_ci
487141cc406Sopenharmony_ci  memset (dev, 0, sizeof (*dev));
488141cc406Sopenharmony_ci  dev->name = strdup (devname);
489141cc406Sopenharmony_ci  dev->sane.name = (SANE_String_Const) dev->name;
490141cc406Sopenharmony_ci  dev->sane.vendor = "Mustek";
491141cc406Sopenharmony_ci  switch (scanner_type)
492141cc406Sopenharmony_ci    {
493141cc406Sopenharmony_ci    case MT_1200CU:
494141cc406Sopenharmony_ci      dev->sane.model = "1200 CU";
495141cc406Sopenharmony_ci      break;
496141cc406Sopenharmony_ci    case MT_1200CU_PLUS:
497141cc406Sopenharmony_ci      dev->sane.model = "1200 CU Plus";
498141cc406Sopenharmony_ci      break;
499141cc406Sopenharmony_ci    case MT_1200USB:
500141cc406Sopenharmony_ci      dev->sane.model = "1200 USB (unsupported)";
501141cc406Sopenharmony_ci      break;
502141cc406Sopenharmony_ci    case MT_1200UB:
503141cc406Sopenharmony_ci      dev->sane.model = "1200 UB";
504141cc406Sopenharmony_ci      break;
505141cc406Sopenharmony_ci    case MT_600CU:
506141cc406Sopenharmony_ci      dev->sane.model = "600 CU";
507141cc406Sopenharmony_ci      break;
508141cc406Sopenharmony_ci    case MT_600USB:
509141cc406Sopenharmony_ci      dev->sane.model = "600 USB (unsupported)";
510141cc406Sopenharmony_ci      break;
511141cc406Sopenharmony_ci    default:
512141cc406Sopenharmony_ci      dev->sane.model = "(unidentified)";
513141cc406Sopenharmony_ci      break;
514141cc406Sopenharmony_ci    }
515141cc406Sopenharmony_ci  dev->sane.type = "flatbed scanner";
516141cc406Sopenharmony_ci
517141cc406Sopenharmony_ci  dev->x_range.min = 0;
518141cc406Sopenharmony_ci  dev->x_range.max = SANE_FIX (8.4 * MM_PER_INCH);
519141cc406Sopenharmony_ci  dev->x_range.quant = 0;
520141cc406Sopenharmony_ci
521141cc406Sopenharmony_ci  dev->y_range.min = 0;
522141cc406Sopenharmony_ci  dev->y_range.max = SANE_FIX (11.7 * MM_PER_INCH);
523141cc406Sopenharmony_ci  dev->y_range.quant = 0;
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci  dev->max_height = 11.7 * 300;
526141cc406Sopenharmony_ci  dev->max_width = 8.4 * 300;
527141cc406Sopenharmony_ci  dev->dpi_range.min = SANE_FIX (50);
528141cc406Sopenharmony_ci  dev->dpi_range.max = SANE_FIX (600);
529141cc406Sopenharmony_ci  dev->dpi_range.quant = SANE_FIX (1);
530141cc406Sopenharmony_ci
531141cc406Sopenharmony_ci  status = usb_high_scan_init (dev);
532141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
533141cc406Sopenharmony_ci    {
534141cc406Sopenharmony_ci      DBG (1, "attach: usb_high_scan_init returned status: %s\n",
535141cc406Sopenharmony_ci	   sane_strstatus (status));
536141cc406Sopenharmony_ci      free (dev);
537141cc406Sopenharmony_ci      return status;
538141cc406Sopenharmony_ci    }
539141cc406Sopenharmony_ci  dev->chip->scanner_type = scanner_type;
540141cc406Sopenharmony_ci  dev->chip->max_block_size = max_block_size;
541141cc406Sopenharmony_ci
542141cc406Sopenharmony_ci  DBG (2, "attach: found %s %s %s at %s\n", dev->sane.vendor, dev->sane.type,
543141cc406Sopenharmony_ci       dev->sane.model, dev->sane.name);
544141cc406Sopenharmony_ci  ++num_devices;
545141cc406Sopenharmony_ci  dev->next = first_dev;
546141cc406Sopenharmony_ci  first_dev = dev;
547141cc406Sopenharmony_ci
548141cc406Sopenharmony_ci  if (devp)
549141cc406Sopenharmony_ci    *devp = dev;
550141cc406Sopenharmony_ci
551141cc406Sopenharmony_ci  DBG (5, "attach: exit\n");
552141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
553141cc406Sopenharmony_ci}
554141cc406Sopenharmony_ci
555141cc406Sopenharmony_cistatic SANE_Status
556141cc406Sopenharmony_ciattach_one_device (SANE_String_Const devname)
557141cc406Sopenharmony_ci{
558141cc406Sopenharmony_ci  Mustek_Usb_Device *dev;
559141cc406Sopenharmony_ci  SANE_Status status;
560141cc406Sopenharmony_ci
561141cc406Sopenharmony_ci  RIE (attach (devname, &dev, SANE_FALSE));
562141cc406Sopenharmony_ci
563141cc406Sopenharmony_ci  if (dev)
564141cc406Sopenharmony_ci    {
565141cc406Sopenharmony_ci      /* Keep track of newly attached devices so we can set options as
566141cc406Sopenharmony_ci         necessary.  */
567141cc406Sopenharmony_ci      if (new_dev_len >= new_dev_alloced)
568141cc406Sopenharmony_ci	{
569141cc406Sopenharmony_ci	  new_dev_alloced += 4;
570141cc406Sopenharmony_ci	  if (new_dev)
571141cc406Sopenharmony_ci	    new_dev =
572141cc406Sopenharmony_ci	      realloc (new_dev, new_dev_alloced * sizeof (new_dev[0]));
573141cc406Sopenharmony_ci	  else
574141cc406Sopenharmony_ci	    new_dev = malloc (new_dev_alloced * sizeof (new_dev[0]));
575141cc406Sopenharmony_ci	  if (!new_dev)
576141cc406Sopenharmony_ci	    {
577141cc406Sopenharmony_ci	      DBG (1, "attach_one_device: out of memory\n");
578141cc406Sopenharmony_ci	      return SANE_STATUS_NO_MEM;
579141cc406Sopenharmony_ci	    }
580141cc406Sopenharmony_ci	}
581141cc406Sopenharmony_ci      new_dev[new_dev_len++] = dev;
582141cc406Sopenharmony_ci    }
583141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
584141cc406Sopenharmony_ci}
585141cc406Sopenharmony_ci
586141cc406Sopenharmony_cistatic SANE_Status
587141cc406Sopenharmony_cifit_lines (Mustek_Usb_Scanner * s, SANE_Byte * src, SANE_Byte * dst,
588141cc406Sopenharmony_ci	   SANE_Word src_lines, SANE_Word * dst_lines)
589141cc406Sopenharmony_ci{
590141cc406Sopenharmony_ci  SANE_Int threshold;
591141cc406Sopenharmony_ci  SANE_Word src_width, dst_width;
592141cc406Sopenharmony_ci  SANE_Word dst_pixel, src_pixel;
593141cc406Sopenharmony_ci  SANE_Word dst_line, src_line;
594141cc406Sopenharmony_ci  SANE_Word pixel_switch;
595141cc406Sopenharmony_ci  SANE_Word src_address, dst_address;
596141cc406Sopenharmony_ci  src_width = s->hw->width;
597141cc406Sopenharmony_ci  dst_width = s->width_dots;
598141cc406Sopenharmony_ci
599141cc406Sopenharmony_ci  threshold = s->val[OPT_THRESHOLD].w;
600141cc406Sopenharmony_ci
601141cc406Sopenharmony_ci  DBG (5, "fit_lines: dst_width=%d, src_width=%d, src_lines=%d, "
602141cc406Sopenharmony_ci       "offset=%d\n", dst_width, src_width, src_lines, s->hw->line_offset);
603141cc406Sopenharmony_ci
604141cc406Sopenharmony_ci  dst_line = 0;
605141cc406Sopenharmony_ci  src_line = s->hw->line_offset;
606141cc406Sopenharmony_ci
607141cc406Sopenharmony_ci  while (src_line < src_lines)
608141cc406Sopenharmony_ci    {
609141cc406Sopenharmony_ci      DBG (5, "fit_lines: getting line: dst_line=%d, src_line=%d, "
610141cc406Sopenharmony_ci	   "line_switch=%d\n", dst_line, src_line, s->hw->line_switch);
611141cc406Sopenharmony_ci
612141cc406Sopenharmony_ci      src_pixel = 0;
613141cc406Sopenharmony_ci      pixel_switch = src_width;
614141cc406Sopenharmony_ci      for (dst_pixel = 0; dst_pixel < dst_width; dst_pixel++)
615141cc406Sopenharmony_ci	{
616141cc406Sopenharmony_ci	  while (pixel_switch > dst_width)
617141cc406Sopenharmony_ci	    {
618141cc406Sopenharmony_ci	      src_pixel++;
619141cc406Sopenharmony_ci	      pixel_switch -= dst_width;
620141cc406Sopenharmony_ci	    }
621141cc406Sopenharmony_ci	  pixel_switch += src_width;
622141cc406Sopenharmony_ci
623141cc406Sopenharmony_ci	  src_address = src_pixel * s->hw->bpp / 8
624141cc406Sopenharmony_ci	    + src_width * src_line * s->hw->bpp / 8;
625141cc406Sopenharmony_ci	  dst_address = dst_pixel * s->bpp / 8
626141cc406Sopenharmony_ci	    + dst_width * dst_line * s->bpp / 8;
627141cc406Sopenharmony_ci
628141cc406Sopenharmony_ci	  if (s->bpp == 8)
629141cc406Sopenharmony_ci	    {
630141cc406Sopenharmony_ci	      dst[dst_address] = s->gray_table[src[src_address]];
631141cc406Sopenharmony_ci	    }
632141cc406Sopenharmony_ci	  else if (s->bpp == 24)
633141cc406Sopenharmony_ci	    {
634141cc406Sopenharmony_ci	      dst[dst_address]
635141cc406Sopenharmony_ci		= s->red_table[s->gray_table[src[src_address]]];
636141cc406Sopenharmony_ci	      dst[dst_address + 1]
637141cc406Sopenharmony_ci		= s->green_table[s->gray_table[src[src_address + 1]]];
638141cc406Sopenharmony_ci	      dst[dst_address + 2]
639141cc406Sopenharmony_ci		= s->blue_table[s->gray_table[src[src_address + 2]]];
640141cc406Sopenharmony_ci	    }
641141cc406Sopenharmony_ci	  else			/* lineart */
642141cc406Sopenharmony_ci	    {
643141cc406Sopenharmony_ci	      if ((dst_pixel % 8) == 0)
644141cc406Sopenharmony_ci		dst[dst_address] = 0;
645141cc406Sopenharmony_ci	      dst[dst_address] |=
646141cc406Sopenharmony_ci		(((src[src_address] > threshold) ? 0 : 1)
647141cc406Sopenharmony_ci		 << (7 - (dst_pixel % 8)));
648141cc406Sopenharmony_ci	    }
649141cc406Sopenharmony_ci	}
650141cc406Sopenharmony_ci
651141cc406Sopenharmony_ci      dst_line++;
652141cc406Sopenharmony_ci      while (s->hw->line_switch >= s->height_dots)
653141cc406Sopenharmony_ci	{
654141cc406Sopenharmony_ci	  src_line++;
655141cc406Sopenharmony_ci	  s->hw->line_switch -= s->height_dots;
656141cc406Sopenharmony_ci	}
657141cc406Sopenharmony_ci      s->hw->line_switch += s->hw->height;
658141cc406Sopenharmony_ci    }
659141cc406Sopenharmony_ci
660141cc406Sopenharmony_ci  *dst_lines = dst_line;
661141cc406Sopenharmony_ci  s->hw->line_offset = (src_line - src_lines);
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci  DBG (4, "fit_lines: exit, src_line=%d, *dst_lines=%d, offset=%d\n",
664141cc406Sopenharmony_ci       src_line, *dst_lines, s->hw->line_offset);
665141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
666141cc406Sopenharmony_ci}
667141cc406Sopenharmony_ci
668141cc406Sopenharmony_cistatic SANE_Status
669141cc406Sopenharmony_cicheck_gamma_table (SANE_Word * table)
670141cc406Sopenharmony_ci{
671141cc406Sopenharmony_ci  SANE_Word entry, value;
672141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
673141cc406Sopenharmony_ci
674141cc406Sopenharmony_ci  for (entry = 0; entry < 256; entry++)
675141cc406Sopenharmony_ci    {
676141cc406Sopenharmony_ci      value = table[entry];
677141cc406Sopenharmony_ci      if (value > 255)
678141cc406Sopenharmony_ci	{
679141cc406Sopenharmony_ci	  DBG (1, "check_gamma_table: warning: entry %d > 255 (%d) - fixed\n",
680141cc406Sopenharmony_ci	       entry, value);
681141cc406Sopenharmony_ci	  table[entry] = 255;
682141cc406Sopenharmony_ci	  status = SANE_STATUS_INVAL;
683141cc406Sopenharmony_ci	}
684141cc406Sopenharmony_ci    }
685141cc406Sopenharmony_ci
686141cc406Sopenharmony_ci  return status;
687141cc406Sopenharmony_ci}
688141cc406Sopenharmony_ci
689141cc406Sopenharmony_ci/* -------------------------- SANE API functions ------------------------- */
690141cc406Sopenharmony_ci
691141cc406Sopenharmony_ciSANE_Status
692141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
693141cc406Sopenharmony_ci{
694141cc406Sopenharmony_ci  SANE_Char line[PATH_MAX];
695141cc406Sopenharmony_ci  SANE_Char *word, *end;
696141cc406Sopenharmony_ci  SANE_String_Const cp;
697141cc406Sopenharmony_ci  SANE_Int linenumber;
698141cc406Sopenharmony_ci  FILE *fp;
699141cc406Sopenharmony_ci
700141cc406Sopenharmony_ci  DBG_INIT ();
701141cc406Sopenharmony_ci  DBG (2, "SANE Mustek USB backend version %d.%d build %d from %s\n", SANE_CURRENT_MAJOR,
702141cc406Sopenharmony_ci       SANE_CURRENT_MINOR, BUILD, PACKAGE_STRING);
703141cc406Sopenharmony_ci
704141cc406Sopenharmony_ci  if (version_code)
705141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
706141cc406Sopenharmony_ci
707141cc406Sopenharmony_ci  DBG (5, "sane_init: authorize %s null\n", authorize ? "!=" : "==");
708141cc406Sopenharmony_ci
709141cc406Sopenharmony_ci
710141cc406Sopenharmony_ci  num_devices = 0;
711141cc406Sopenharmony_ci  first_dev = 0;
712141cc406Sopenharmony_ci  first_handle = 0;
713141cc406Sopenharmony_ci  devlist = 0;
714141cc406Sopenharmony_ci  new_dev = 0;
715141cc406Sopenharmony_ci  new_dev_len = 0;
716141cc406Sopenharmony_ci  new_dev_alloced = 0;
717141cc406Sopenharmony_ci
718141cc406Sopenharmony_ci  sanei_usb_init ();
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci  fp = sanei_config_open (MUSTEK_USB_CONFIG_FILE);
721141cc406Sopenharmony_ci  if (!fp)
722141cc406Sopenharmony_ci    {
723141cc406Sopenharmony_ci      /* default to /dev/usb/scanner instead of insisting on config file */
724141cc406Sopenharmony_ci      DBG (3, "sane_init: couldn't open config file `%s': %s. Using "
725141cc406Sopenharmony_ci	   "/dev/usb/scanner directly\n", MUSTEK_USB_CONFIG_FILE,
726141cc406Sopenharmony_ci	   strerror (errno));
727141cc406Sopenharmony_ci      attach ("/dev/usb/scanner", 0, SANE_FALSE);
728141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
729141cc406Sopenharmony_ci    }
730141cc406Sopenharmony_ci  linenumber = 0;
731141cc406Sopenharmony_ci  DBG (4, "sane_init: reading config file `%s'\n", MUSTEK_USB_CONFIG_FILE);
732141cc406Sopenharmony_ci
733141cc406Sopenharmony_ci  while (sanei_config_read (line, sizeof (line), fp))
734141cc406Sopenharmony_ci    {
735141cc406Sopenharmony_ci      word = 0;
736141cc406Sopenharmony_ci      linenumber++;
737141cc406Sopenharmony_ci
738141cc406Sopenharmony_ci      cp = sanei_config_get_string (line, &word);
739141cc406Sopenharmony_ci      if (!word || cp == line)
740141cc406Sopenharmony_ci	{
741141cc406Sopenharmony_ci	  DBG (5, "sane_init: config file line %d: ignoring empty line\n",
742141cc406Sopenharmony_ci	       linenumber);
743141cc406Sopenharmony_ci	  if (word)
744141cc406Sopenharmony_ci	    free (word);
745141cc406Sopenharmony_ci	  continue;
746141cc406Sopenharmony_ci	}
747141cc406Sopenharmony_ci      if (word[0] == '#')
748141cc406Sopenharmony_ci	{
749141cc406Sopenharmony_ci	  DBG (5, "sane_init: config file line %d: ignoring comment line\n",
750141cc406Sopenharmony_ci	       linenumber);
751141cc406Sopenharmony_ci	  free (word);
752141cc406Sopenharmony_ci	  continue;
753141cc406Sopenharmony_ci	}
754141cc406Sopenharmony_ci
755141cc406Sopenharmony_ci      if (strcmp (word, "option") == 0)
756141cc406Sopenharmony_ci	{
757141cc406Sopenharmony_ci	  free (word);
758141cc406Sopenharmony_ci	  word = 0;
759141cc406Sopenharmony_ci	  cp = sanei_config_get_string (cp, &word);
760141cc406Sopenharmony_ci
761141cc406Sopenharmony_ci	  if (!word)
762141cc406Sopenharmony_ci	    {
763141cc406Sopenharmony_ci	      DBG (1, "sane_init: config file line %d: missing quotation mark?\n",
764141cc406Sopenharmony_ci		   linenumber);
765141cc406Sopenharmony_ci	      continue;
766141cc406Sopenharmony_ci	    }
767141cc406Sopenharmony_ci
768141cc406Sopenharmony_ci	  if (strcmp (word, "max_block_size") == 0)
769141cc406Sopenharmony_ci	    {
770141cc406Sopenharmony_ci	      free (word);
771141cc406Sopenharmony_ci	      word = 0;
772141cc406Sopenharmony_ci	      cp = sanei_config_get_string (cp, &word);
773141cc406Sopenharmony_ci	      if (!word)
774141cc406Sopenharmony_ci		{
775141cc406Sopenharmony_ci		  DBG (1, "sane_init: config file line %d: missing quotation mark?\n",
776141cc406Sopenharmony_ci		       linenumber);
777141cc406Sopenharmony_ci		  continue;
778141cc406Sopenharmony_ci		}
779141cc406Sopenharmony_ci
780141cc406Sopenharmony_ci	      errno = 0;
781141cc406Sopenharmony_ci	      max_block_size = strtol (word, &end, 0);
782141cc406Sopenharmony_ci	      if (end == word)
783141cc406Sopenharmony_ci		{
784141cc406Sopenharmony_ci		  DBG (3, "sane-init: config file line %d: max_block_size "
785141cc406Sopenharmony_ci		       "must have a parameter; using 8192 bytes\n",
786141cc406Sopenharmony_ci		       linenumber);
787141cc406Sopenharmony_ci		  max_block_size = 8192;
788141cc406Sopenharmony_ci		}
789141cc406Sopenharmony_ci	      if (errno)
790141cc406Sopenharmony_ci		{
791141cc406Sopenharmony_ci		  DBG (3,
792141cc406Sopenharmony_ci		       "sane-init: config file line %d: max_block_size `%s' "
793141cc406Sopenharmony_ci		       "is invalid (%s); using 8192 bytes\n", linenumber,
794141cc406Sopenharmony_ci		       word, strerror (errno));
795141cc406Sopenharmony_ci		  max_block_size = 8192;
796141cc406Sopenharmony_ci		}
797141cc406Sopenharmony_ci	      else
798141cc406Sopenharmony_ci		{
799141cc406Sopenharmony_ci		  DBG (3,
800141cc406Sopenharmony_ci		       "sane_init: config file line %d: max_block_size set "
801141cc406Sopenharmony_ci		       "to %d bytes\n", linenumber, max_block_size);
802141cc406Sopenharmony_ci		}
803141cc406Sopenharmony_ci	      if (word)
804141cc406Sopenharmony_ci		free (word);
805141cc406Sopenharmony_ci	      word = 0;
806141cc406Sopenharmony_ci	    }
807141cc406Sopenharmony_ci	  else if (strcmp (word, "1200ub") == 0)
808141cc406Sopenharmony_ci	    {
809141cc406Sopenharmony_ci	      if (new_dev_len > 0)
810141cc406Sopenharmony_ci		{
811141cc406Sopenharmony_ci		  /* this is a 1200 UB */
812141cc406Sopenharmony_ci		  new_dev[new_dev_len - 1]->chip->scanner_type = MT_1200UB;
813141cc406Sopenharmony_ci		  new_dev[new_dev_len - 1]->sane.model = "1200 UB";
814141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: `%s' is a Mustek "
815141cc406Sopenharmony_ci		       "1200 UB\n", linenumber,
816141cc406Sopenharmony_ci		       new_dev[new_dev_len - 1]->sane.name);
817141cc406Sopenharmony_ci		}
818141cc406Sopenharmony_ci	      else
819141cc406Sopenharmony_ci		{
820141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: option "
821141cc406Sopenharmony_ci		       "1200ub ignored, was set before any device "
822141cc406Sopenharmony_ci		       "name\n", linenumber);
823141cc406Sopenharmony_ci		}
824141cc406Sopenharmony_ci	      if (word)
825141cc406Sopenharmony_ci		free (word);
826141cc406Sopenharmony_ci	      word = 0;
827141cc406Sopenharmony_ci	    }
828141cc406Sopenharmony_ci	  else if (strcmp (word, "1200cu") == 0)
829141cc406Sopenharmony_ci	    {
830141cc406Sopenharmony_ci	      if (new_dev_len > 0)
831141cc406Sopenharmony_ci		{
832141cc406Sopenharmony_ci		  /* this is a 1200 CU */
833141cc406Sopenharmony_ci		  new_dev[new_dev_len - 1]->chip->scanner_type = MT_1200CU;
834141cc406Sopenharmony_ci		  new_dev[new_dev_len - 1]->sane.model = "1200 CU";
835141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: `%s' is a Mustek "
836141cc406Sopenharmony_ci		       "1200 CU\n", linenumber,
837141cc406Sopenharmony_ci		       new_dev[new_dev_len - 1]->sane.name);
838141cc406Sopenharmony_ci		}
839141cc406Sopenharmony_ci	      else
840141cc406Sopenharmony_ci		{
841141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: option "
842141cc406Sopenharmony_ci		       "1200cu ignored, was set before any device "
843141cc406Sopenharmony_ci		       "name\n", linenumber);
844141cc406Sopenharmony_ci		}
845141cc406Sopenharmony_ci	      if (word)
846141cc406Sopenharmony_ci		free (word);
847141cc406Sopenharmony_ci	      word = 0;
848141cc406Sopenharmony_ci	    }
849141cc406Sopenharmony_ci	  else if (strcmp (word, "1200cu_plus") == 0)
850141cc406Sopenharmony_ci	    {
851141cc406Sopenharmony_ci	      if (new_dev_len > 0)
852141cc406Sopenharmony_ci		{
853141cc406Sopenharmony_ci		  /* this is a 1200 CU Plus */
854141cc406Sopenharmony_ci		  new_dev[new_dev_len - 1]->chip->scanner_type
855141cc406Sopenharmony_ci		    = MT_1200CU_PLUS;
856141cc406Sopenharmony_ci		  new_dev[new_dev_len - 1]->sane.model = "1200 CU Plus";
857141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: `%s' is a Mustek "
858141cc406Sopenharmony_ci		       "1200 CU Plus\n", linenumber,
859141cc406Sopenharmony_ci		       new_dev[new_dev_len - 1]->sane.name);
860141cc406Sopenharmony_ci		}
861141cc406Sopenharmony_ci	      else
862141cc406Sopenharmony_ci		{
863141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: option "
864141cc406Sopenharmony_ci		       "1200cu_plus ignored, was set before any device "
865141cc406Sopenharmony_ci		       "name\n", linenumber);
866141cc406Sopenharmony_ci		}
867141cc406Sopenharmony_ci	      if (word)
868141cc406Sopenharmony_ci		free (word);
869141cc406Sopenharmony_ci	      word = 0;
870141cc406Sopenharmony_ci	    }
871141cc406Sopenharmony_ci	  else if (strcmp (word, "600cu") == 0)
872141cc406Sopenharmony_ci	    {
873141cc406Sopenharmony_ci	      if (new_dev_len > 0)
874141cc406Sopenharmony_ci		{
875141cc406Sopenharmony_ci		  /* this is a 600 CU */
876141cc406Sopenharmony_ci		  new_dev[new_dev_len - 1]->chip->scanner_type = MT_600CU;
877141cc406Sopenharmony_ci		  new_dev[new_dev_len - 1]->sane.model = "600 CU";
878141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: `%s' is a Mustek "
879141cc406Sopenharmony_ci		       "600 CU\n", linenumber,
880141cc406Sopenharmony_ci		       new_dev[new_dev_len - 1]->sane.name);
881141cc406Sopenharmony_ci		}
882141cc406Sopenharmony_ci	      else
883141cc406Sopenharmony_ci		{
884141cc406Sopenharmony_ci		  DBG (3, "sane_init: config file line %d: option "
885141cc406Sopenharmony_ci		       "600cu ignored, was set before any device "
886141cc406Sopenharmony_ci		       "name\n", linenumber);
887141cc406Sopenharmony_ci		}
888141cc406Sopenharmony_ci	      if (word)
889141cc406Sopenharmony_ci		free (word);
890141cc406Sopenharmony_ci	      word = 0;
891141cc406Sopenharmony_ci	    }
892141cc406Sopenharmony_ci	  else
893141cc406Sopenharmony_ci	    {
894141cc406Sopenharmony_ci	      DBG (3, "sane_init: config file line %d: option "
895141cc406Sopenharmony_ci		   "%s is unknown\n", linenumber, word);
896141cc406Sopenharmony_ci	      if (word)
897141cc406Sopenharmony_ci		free (word);
898141cc406Sopenharmony_ci	      word = 0;
899141cc406Sopenharmony_ci	    }
900141cc406Sopenharmony_ci	}
901141cc406Sopenharmony_ci      else
902141cc406Sopenharmony_ci	{
903141cc406Sopenharmony_ci	  new_dev_len = 0;
904141cc406Sopenharmony_ci	  DBG (4, "sane_init: config file line %d: trying to attach `%s'\n",
905141cc406Sopenharmony_ci	       linenumber, line);
906141cc406Sopenharmony_ci	  sanei_usb_attach_matching_devices (line, attach_one_device);
907141cc406Sopenharmony_ci	  if (word)
908141cc406Sopenharmony_ci	    free (word);
909141cc406Sopenharmony_ci	  word = 0;
910141cc406Sopenharmony_ci	}
911141cc406Sopenharmony_ci    }
912141cc406Sopenharmony_ci
913141cc406Sopenharmony_ci  if (new_dev_alloced > 0)
914141cc406Sopenharmony_ci    {
915141cc406Sopenharmony_ci      new_dev_len = new_dev_alloced = 0;
916141cc406Sopenharmony_ci      free (new_dev);
917141cc406Sopenharmony_ci    }
918141cc406Sopenharmony_ci
919141cc406Sopenharmony_ci  fclose (fp);
920141cc406Sopenharmony_ci  DBG (5, "sane_init: exit\n");
921141cc406Sopenharmony_ci
922141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
923141cc406Sopenharmony_ci}
924141cc406Sopenharmony_ci
925141cc406Sopenharmony_civoid
926141cc406Sopenharmony_cisane_exit (void)
927141cc406Sopenharmony_ci{
928141cc406Sopenharmony_ci  Mustek_Usb_Device *dev, *next;
929141cc406Sopenharmony_ci  SANE_Status status;
930141cc406Sopenharmony_ci
931141cc406Sopenharmony_ci  DBG (5, "sane_exit: start\n");
932141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = next)
933141cc406Sopenharmony_ci    {
934141cc406Sopenharmony_ci      next = dev->next;
935141cc406Sopenharmony_ci      if (dev->is_prepared)
936141cc406Sopenharmony_ci	{
937141cc406Sopenharmony_ci	  status = usb_high_scan_clearup (dev);
938141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
939141cc406Sopenharmony_ci	    DBG (3, "sane_close: usb_high_scan_clearup returned %s\n",
940141cc406Sopenharmony_ci		 sane_strstatus (status));
941141cc406Sopenharmony_ci	}
942141cc406Sopenharmony_ci      status = usb_high_scan_exit (dev);
943141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
944141cc406Sopenharmony_ci	DBG (3, "sane_close: usb_high_scan_exit returned %s\n",
945141cc406Sopenharmony_ci	     sane_strstatus (status));
946141cc406Sopenharmony_ci      if (dev->chip)
947141cc406Sopenharmony_ci	{
948141cc406Sopenharmony_ci	  status = usb_high_scan_exit (dev);
949141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
950141cc406Sopenharmony_ci	    DBG (3,
951141cc406Sopenharmony_ci		 "sane_exit: while closing %s, usb_high_scan_exit returned: "
952141cc406Sopenharmony_ci		 "%s\n", dev->name, sane_strstatus (status));
953141cc406Sopenharmony_ci	}
954141cc406Sopenharmony_ci      free ((void *) dev->name);
955141cc406Sopenharmony_ci      free (dev);
956141cc406Sopenharmony_ci    }
957141cc406Sopenharmony_ci  first_dev = 0;
958141cc406Sopenharmony_ci  if (devlist)
959141cc406Sopenharmony_ci    free (devlist);
960141cc406Sopenharmony_ci  devlist = 0;
961141cc406Sopenharmony_ci
962141cc406Sopenharmony_ci  DBG (5, "sane_exit: exit\n");
963141cc406Sopenharmony_ci}
964141cc406Sopenharmony_ci
965141cc406Sopenharmony_ciSANE_Status
966141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
967141cc406Sopenharmony_ci{
968141cc406Sopenharmony_ci  Mustek_Usb_Device *dev;
969141cc406Sopenharmony_ci  SANE_Int dev_num;
970141cc406Sopenharmony_ci
971141cc406Sopenharmony_ci  DBG (5, "sane_get_devices: start: local_only = %s\n",
972141cc406Sopenharmony_ci       local_only == SANE_TRUE ? "true" : "false");
973141cc406Sopenharmony_ci
974141cc406Sopenharmony_ci  if (devlist)
975141cc406Sopenharmony_ci    free (devlist);
976141cc406Sopenharmony_ci
977141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
978141cc406Sopenharmony_ci  if (!devlist)
979141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
980141cc406Sopenharmony_ci
981141cc406Sopenharmony_ci  dev_num = 0;
982141cc406Sopenharmony_ci  for (dev = first_dev; dev_num < num_devices; dev = dev->next)
983141cc406Sopenharmony_ci    devlist[dev_num++] = &dev->sane;
984141cc406Sopenharmony_ci  devlist[dev_num++] = 0;
985141cc406Sopenharmony_ci
986141cc406Sopenharmony_ci  *device_list = devlist;
987141cc406Sopenharmony_ci
988141cc406Sopenharmony_ci  DBG (5, "sane_get_devices: exit\n");
989141cc406Sopenharmony_ci
990141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
991141cc406Sopenharmony_ci}
992141cc406Sopenharmony_ci
993141cc406Sopenharmony_ciSANE_Status
994141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
995141cc406Sopenharmony_ci{
996141cc406Sopenharmony_ci  Mustek_Usb_Device *dev;
997141cc406Sopenharmony_ci  SANE_Status status;
998141cc406Sopenharmony_ci  Mustek_Usb_Scanner *s;
999141cc406Sopenharmony_ci  SANE_Int value;
1000141cc406Sopenharmony_ci
1001141cc406Sopenharmony_ci  DBG (5, "sane_open: start (devicename = `%s')\n", devicename);
1002141cc406Sopenharmony_ci
1003141cc406Sopenharmony_ci  if (devicename[0])
1004141cc406Sopenharmony_ci    {
1005141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
1006141cc406Sopenharmony_ci	if (strcmp (dev->sane.name, devicename) == 0)
1007141cc406Sopenharmony_ci	  break;
1008141cc406Sopenharmony_ci
1009141cc406Sopenharmony_ci      if (!dev)
1010141cc406Sopenharmony_ci	{
1011141cc406Sopenharmony_ci	  DBG (5,
1012141cc406Sopenharmony_ci	       "sane_open: couldn't find `%s' in devlist, trying attach)\n",
1013141cc406Sopenharmony_ci	       devicename);
1014141cc406Sopenharmony_ci	  RIE (attach (devicename, &dev, SANE_TRUE));
1015141cc406Sopenharmony_ci	}
1016141cc406Sopenharmony_ci      else
1017141cc406Sopenharmony_ci	DBG (5, "sane_open: found `%s' in devlist\n", dev->name);
1018141cc406Sopenharmony_ci    }
1019141cc406Sopenharmony_ci  else
1020141cc406Sopenharmony_ci    {
1021141cc406Sopenharmony_ci      /* empty devicname -> use first device */
1022141cc406Sopenharmony_ci      dev = first_dev;
1023141cc406Sopenharmony_ci      if (dev)
1024141cc406Sopenharmony_ci	DBG (5, "sane_open: empty devicename, trying `%s'\n", dev->name);
1025141cc406Sopenharmony_ci    }
1026141cc406Sopenharmony_ci
1027141cc406Sopenharmony_ci  if (!dev)
1028141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1029141cc406Sopenharmony_ci
1030141cc406Sopenharmony_ci  if (dev->chip->scanner_type == MT_UNKNOWN)
1031141cc406Sopenharmony_ci    {
1032141cc406Sopenharmony_ci      DBG (0, "sane_open: the type of your scanner is unknown, edit "
1033141cc406Sopenharmony_ci	   "mustek_usb.conf before using the scanner\n");
1034141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1035141cc406Sopenharmony_ci    }
1036141cc406Sopenharmony_ci  s = malloc (sizeof (*s));
1037141cc406Sopenharmony_ci  if (!s)
1038141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1039141cc406Sopenharmony_ci  memset (s, 0, sizeof (*s));
1040141cc406Sopenharmony_ci  s->hw = dev;
1041141cc406Sopenharmony_ci
1042141cc406Sopenharmony_ci  RIE (init_options (s));
1043141cc406Sopenharmony_ci
1044141cc406Sopenharmony_ci  /* insert newly opened handle into list of open handles: */
1045141cc406Sopenharmony_ci  s->next = first_handle;
1046141cc406Sopenharmony_ci  first_handle = s;
1047141cc406Sopenharmony_ci
1048141cc406Sopenharmony_ci  *handle = s;
1049141cc406Sopenharmony_ci  strcpy (s->hw->device_name, dev->name);
1050141cc406Sopenharmony_ci
1051141cc406Sopenharmony_ci  RIE (usb_high_scan_turn_power (s->hw, SANE_TRUE));
1052141cc406Sopenharmony_ci  RIE (usb_high_scan_back_home (s->hw));
1053141cc406Sopenharmony_ci
1054141cc406Sopenharmony_ci  s->hw->scan_buffer = (SANE_Byte *) malloc (SCAN_BUFFER_SIZE * 2);
1055141cc406Sopenharmony_ci  if (!s->hw->scan_buffer)
1056141cc406Sopenharmony_ci    {
1057141cc406Sopenharmony_ci      DBG (5, "sane_open: couldn't malloc s->hw->scan_buffer (%d bytes)\n",
1058141cc406Sopenharmony_ci	   SCAN_BUFFER_SIZE * 2);
1059141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1060141cc406Sopenharmony_ci    }
1061141cc406Sopenharmony_ci  s->hw->scan_buffer_len = 0;
1062141cc406Sopenharmony_ci  s->hw->scan_buffer_start = s->hw->scan_buffer;
1063141cc406Sopenharmony_ci
1064141cc406Sopenharmony_ci  s->hw->temp_buffer = (SANE_Byte *) malloc (SCAN_BUFFER_SIZE);
1065141cc406Sopenharmony_ci  if (!s->hw->temp_buffer)
1066141cc406Sopenharmony_ci    {
1067141cc406Sopenharmony_ci      DBG (5, "sane_open: couldn't malloc s->hw->temp_buffer (%d bytes)\n",
1068141cc406Sopenharmony_ci	   SCAN_BUFFER_SIZE);
1069141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1070141cc406Sopenharmony_ci    }
1071141cc406Sopenharmony_ci  s->hw->temp_buffer_len = 0;
1072141cc406Sopenharmony_ci  s->hw->temp_buffer_start = s->hw->temp_buffer;
1073141cc406Sopenharmony_ci
1074141cc406Sopenharmony_ci  for (value = 0; value < 256; value++)
1075141cc406Sopenharmony_ci    {
1076141cc406Sopenharmony_ci      s->linear_gamma_table[value] = value;
1077141cc406Sopenharmony_ci      s->red_gamma_table[value] = value;
1078141cc406Sopenharmony_ci      s->green_gamma_table[value] = value;
1079141cc406Sopenharmony_ci      s->blue_gamma_table[value] = value;
1080141cc406Sopenharmony_ci      s->gray_gamma_table[value] = value;
1081141cc406Sopenharmony_ci    }
1082141cc406Sopenharmony_ci
1083141cc406Sopenharmony_ci  s->red_table = s->linear_gamma_table;
1084141cc406Sopenharmony_ci  s->green_table = s->linear_gamma_table;
1085141cc406Sopenharmony_ci  s->blue_table = s->linear_gamma_table;
1086141cc406Sopenharmony_ci  s->gray_table = s->linear_gamma_table;
1087141cc406Sopenharmony_ci
1088141cc406Sopenharmony_ci  DBG (5, "sane_open: exit\n");
1089141cc406Sopenharmony_ci
1090141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1091141cc406Sopenharmony_ci}
1092141cc406Sopenharmony_ci
1093141cc406Sopenharmony_civoid
1094141cc406Sopenharmony_cisane_close (SANE_Handle handle)
1095141cc406Sopenharmony_ci{
1096141cc406Sopenharmony_ci  Mustek_Usb_Scanner *prev, *s;
1097141cc406Sopenharmony_ci  SANE_Status status;
1098141cc406Sopenharmony_ci
1099141cc406Sopenharmony_ci  DBG (5, "sane_close: start\n");
1100141cc406Sopenharmony_ci
1101141cc406Sopenharmony_ci  /* remove handle from list of open handles: */
1102141cc406Sopenharmony_ci  prev = 0;
1103141cc406Sopenharmony_ci  for (s = first_handle; s; s = s->next)
1104141cc406Sopenharmony_ci    {
1105141cc406Sopenharmony_ci      if (s == handle)
1106141cc406Sopenharmony_ci	break;
1107141cc406Sopenharmony_ci      prev = s;
1108141cc406Sopenharmony_ci    }
1109141cc406Sopenharmony_ci  if (!s)
1110141cc406Sopenharmony_ci    {
1111141cc406Sopenharmony_ci      DBG (5, "close: invalid handle %p\n", handle);
1112141cc406Sopenharmony_ci      return;			/* oops, not a handle we know about */
1113141cc406Sopenharmony_ci    }
1114141cc406Sopenharmony_ci
1115141cc406Sopenharmony_ci  if (prev)
1116141cc406Sopenharmony_ci    prev->next = s->next;
1117141cc406Sopenharmony_ci  else
1118141cc406Sopenharmony_ci    first_handle = s->next;
1119141cc406Sopenharmony_ci
1120141cc406Sopenharmony_ci  if (s->hw->is_open)
1121141cc406Sopenharmony_ci    {
1122141cc406Sopenharmony_ci      status = usb_high_scan_turn_power (s->hw, SANE_FALSE);
1123141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1124141cc406Sopenharmony_ci	DBG (3, "sane_close: usb_high_scan_turn_power returned %s\n",
1125141cc406Sopenharmony_ci	     sane_strstatus (status));
1126141cc406Sopenharmony_ci    }
1127141cc406Sopenharmony_ci#if 0
1128141cc406Sopenharmony_ci  if (s->hw->is_prepared)
1129141cc406Sopenharmony_ci    {
1130141cc406Sopenharmony_ci      status = usb_high_scan_clearup (s->hw);
1131141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1132141cc406Sopenharmony_ci	DBG (3, "sane_close: usb_high_scan_clearup returned %s\n",
1133141cc406Sopenharmony_ci	     sane_strstatus (status));
1134141cc406Sopenharmony_ci    }
1135141cc406Sopenharmony_ci  status = usb_high_scan_exit (s->hw);
1136141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1137141cc406Sopenharmony_ci    DBG (3, "sane_close: usb_high_scan_exit returned %s\n",
1138141cc406Sopenharmony_ci	 sane_strstatus (status));
1139141cc406Sopenharmony_ci#endif
1140141cc406Sopenharmony_ci  if (s->hw->scan_buffer)
1141141cc406Sopenharmony_ci    {
1142141cc406Sopenharmony_ci      free (s->hw->scan_buffer);
1143141cc406Sopenharmony_ci      s->hw->scan_buffer = 0;
1144141cc406Sopenharmony_ci    }
1145141cc406Sopenharmony_ci  if (s->hw->temp_buffer)
1146141cc406Sopenharmony_ci    {
1147141cc406Sopenharmony_ci      free (s->hw->temp_buffer);
1148141cc406Sopenharmony_ci      s->hw->temp_buffer = 0;
1149141cc406Sopenharmony_ci    }
1150141cc406Sopenharmony_ci
1151141cc406Sopenharmony_ci  free (handle);
1152141cc406Sopenharmony_ci
1153141cc406Sopenharmony_ci  DBG (5, "sane_close: exit\n");
1154141cc406Sopenharmony_ci}
1155141cc406Sopenharmony_ci
1156141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
1157141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
1158141cc406Sopenharmony_ci{
1159141cc406Sopenharmony_ci  Mustek_Usb_Scanner *s = handle;
1160141cc406Sopenharmony_ci
1161141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
1162141cc406Sopenharmony_ci    return 0;
1163141cc406Sopenharmony_ci  DBG (5, "sane_get_option_descriptor: option = %s (%d)\n",
1164141cc406Sopenharmony_ci       s->opt[option].name, option);
1165141cc406Sopenharmony_ci  return s->opt + option;
1166141cc406Sopenharmony_ci}
1167141cc406Sopenharmony_ci
1168141cc406Sopenharmony_ciSANE_Status
1169141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
1170141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
1171141cc406Sopenharmony_ci{
1172141cc406Sopenharmony_ci  Mustek_Usb_Scanner *s = handle;
1173141cc406Sopenharmony_ci  SANE_Status status;
1174141cc406Sopenharmony_ci  SANE_Word cap;
1175141cc406Sopenharmony_ci  SANE_Int myinfo = 0;
1176141cc406Sopenharmony_ci
1177141cc406Sopenharmony_ci  DBG (5, "sane_control_option: start: action = %s, option = %s (%d)\n",
1178141cc406Sopenharmony_ci       (action == SANE_ACTION_GET_VALUE) ? "get" :
1179141cc406Sopenharmony_ci       (action == SANE_ACTION_SET_VALUE) ? "set" :
1180141cc406Sopenharmony_ci       (action == SANE_ACTION_SET_AUTO) ? "set_auto" : "unknown",
1181141cc406Sopenharmony_ci       s->opt[option].name, option);
1182141cc406Sopenharmony_ci
1183141cc406Sopenharmony_ci  if (info)
1184141cc406Sopenharmony_ci    *info = 0;
1185141cc406Sopenharmony_ci
1186141cc406Sopenharmony_ci  if (s->scanning)
1187141cc406Sopenharmony_ci    {
1188141cc406Sopenharmony_ci      DBG (1, "sane_control_option: don't call this function while "
1189141cc406Sopenharmony_ci	   "scanning\n");
1190141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
1191141cc406Sopenharmony_ci    }
1192141cc406Sopenharmony_ci
1193141cc406Sopenharmony_ci  if (option >= NUM_OPTIONS || option < 0)
1194141cc406Sopenharmony_ci    {
1195141cc406Sopenharmony_ci      DBG (1, "sane_control_option: option %d >= NUM_OPTIONS || option < 0\n",
1196141cc406Sopenharmony_ci	   option);
1197141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1198141cc406Sopenharmony_ci    }
1199141cc406Sopenharmony_ci
1200141cc406Sopenharmony_ci  cap = s->opt[option].cap;
1201141cc406Sopenharmony_ci
1202141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
1203141cc406Sopenharmony_ci    {
1204141cc406Sopenharmony_ci      DBG (2, "sane_control_option: option %d is inactive\n", option);
1205141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1206141cc406Sopenharmony_ci    }
1207141cc406Sopenharmony_ci
1208141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
1209141cc406Sopenharmony_ci    {
1210141cc406Sopenharmony_ci      switch (option)
1211141cc406Sopenharmony_ci	{
1212141cc406Sopenharmony_ci	  /* word options: */
1213141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
1214141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1215141cc406Sopenharmony_ci	case OPT_PREVIEW:
1216141cc406Sopenharmony_ci	case OPT_TL_X:
1217141cc406Sopenharmony_ci	case OPT_TL_Y:
1218141cc406Sopenharmony_ci	case OPT_BR_X:
1219141cc406Sopenharmony_ci	case OPT_BR_Y:
1220141cc406Sopenharmony_ci	case OPT_THRESHOLD:
1221141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
1222141cc406Sopenharmony_ci	  *(SANE_Word *) val = s->val[option].w;
1223141cc406Sopenharmony_ci	  break;
1224141cc406Sopenharmony_ci	  /* word-array options: */
1225141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
1226141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
1227141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
1228141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
1229141cc406Sopenharmony_ci	  memcpy (val, s->val[option].wa, s->opt[option].size);
1230141cc406Sopenharmony_ci	  break;
1231141cc406Sopenharmony_ci	  /* string options: */
1232141cc406Sopenharmony_ci	case OPT_MODE:
1233141cc406Sopenharmony_ci	  strcpy (val, s->val[option].s);
1234141cc406Sopenharmony_ci	  break;
1235141cc406Sopenharmony_ci	default:
1236141cc406Sopenharmony_ci	  DBG (2, "sane_control_option: can't get unknown option %d\n",
1237141cc406Sopenharmony_ci	       option);
1238141cc406Sopenharmony_ci	}
1239141cc406Sopenharmony_ci    }
1240141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
1241141cc406Sopenharmony_ci    {
1242141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
1243141cc406Sopenharmony_ci	{
1244141cc406Sopenharmony_ci	  DBG (2, "sane_control_option: option %d is not settable\n", option);
1245141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1246141cc406Sopenharmony_ci	}
1247141cc406Sopenharmony_ci
1248141cc406Sopenharmony_ci      status = sanei_constrain_value (s->opt + option, val, &myinfo);
1249141cc406Sopenharmony_ci
1250141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1251141cc406Sopenharmony_ci	{
1252141cc406Sopenharmony_ci	  DBG (2, "sane_control_option: sanei_constrain_value returned %s\n",
1253141cc406Sopenharmony_ci	       sane_strstatus (status));
1254141cc406Sopenharmony_ci	  return status;
1255141cc406Sopenharmony_ci	}
1256141cc406Sopenharmony_ci
1257141cc406Sopenharmony_ci      switch (option)
1258141cc406Sopenharmony_ci	{
1259141cc406Sopenharmony_ci	  /* (mostly) side-effect-free word options: */
1260141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1261141cc406Sopenharmony_ci	case OPT_TL_X:
1262141cc406Sopenharmony_ci	case OPT_TL_Y:
1263141cc406Sopenharmony_ci	case OPT_BR_X:
1264141cc406Sopenharmony_ci	case OPT_BR_Y:
1265141cc406Sopenharmony_ci	  s->val[option].w = *(SANE_Word *) val;
1266141cc406Sopenharmony_ci	  RIE (calc_parameters (s));
1267141cc406Sopenharmony_ci	  myinfo |= SANE_INFO_RELOAD_PARAMS;
1268141cc406Sopenharmony_ci	  break;
1269141cc406Sopenharmony_ci	case OPT_THRESHOLD:
1270141cc406Sopenharmony_ci	  s->val[option].w = *(SANE_Word *) val;
1271141cc406Sopenharmony_ci	  break;
1272141cc406Sopenharmony_ci	  /* Boolean */
1273141cc406Sopenharmony_ci	case OPT_PREVIEW:
1274141cc406Sopenharmony_ci	  s->val[option].w = *(SANE_Bool *) val;
1275141cc406Sopenharmony_ci	  break;
1276141cc406Sopenharmony_ci	  /* side-effect-free word-array options: */
1277141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
1278141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
1279141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
1280141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
1281141cc406Sopenharmony_ci	  memcpy (s->val[option].wa, val, s->opt[option].size);
1282141cc406Sopenharmony_ci	  check_gamma_table (s->val[option].wa);
1283141cc406Sopenharmony_ci	  break;
1284141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
1285141cc406Sopenharmony_ci	  s->val[OPT_CUSTOM_GAMMA].w = *(SANE_Word *) val;
1286141cc406Sopenharmony_ci	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
1287141cc406Sopenharmony_ci	  if (s->val[OPT_CUSTOM_GAMMA].w == SANE_TRUE)
1288141cc406Sopenharmony_ci	    {
1289141cc406Sopenharmony_ci	      s->red_table = s->red_gamma_table;
1290141cc406Sopenharmony_ci	      s->green_table = s->green_gamma_table;
1291141cc406Sopenharmony_ci	      s->blue_table = s->blue_gamma_table;
1292141cc406Sopenharmony_ci	      s->gray_table = s->gray_gamma_table;
1293141cc406Sopenharmony_ci	      if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1294141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1295141cc406Sopenharmony_ci	      else if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1296141cc406Sopenharmony_ci		{
1297141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1298141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1299141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1300141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1301141cc406Sopenharmony_ci		}
1302141cc406Sopenharmony_ci	    }
1303141cc406Sopenharmony_ci	  else
1304141cc406Sopenharmony_ci	    {
1305141cc406Sopenharmony_ci	      s->red_table = s->linear_gamma_table;
1306141cc406Sopenharmony_ci	      s->green_table = s->linear_gamma_table;
1307141cc406Sopenharmony_ci	      s->blue_table = s->linear_gamma_table;
1308141cc406Sopenharmony_ci	      s->gray_table = s->linear_gamma_table;
1309141cc406Sopenharmony_ci	      s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1310141cc406Sopenharmony_ci	      s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1311141cc406Sopenharmony_ci	      s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1312141cc406Sopenharmony_ci	      s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1313141cc406Sopenharmony_ci	    }
1314141cc406Sopenharmony_ci	  break;
1315141cc406Sopenharmony_ci	case OPT_MODE:
1316141cc406Sopenharmony_ci	  if (s->val[option].s)
1317141cc406Sopenharmony_ci	    free (s->val[option].s);
1318141cc406Sopenharmony_ci	  s->val[option].s = strdup (val);
1319141cc406Sopenharmony_ci
1320141cc406Sopenharmony_ci	  RIE (calc_parameters (s));
1321141cc406Sopenharmony_ci
1322141cc406Sopenharmony_ci	  s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
1323141cc406Sopenharmony_ci	  s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1324141cc406Sopenharmony_ci	  s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1325141cc406Sopenharmony_ci	  s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1326141cc406Sopenharmony_ci	  s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1327141cc406Sopenharmony_ci	  s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1328141cc406Sopenharmony_ci
1329141cc406Sopenharmony_ci	  if (strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0)
1330141cc406Sopenharmony_ci	    {
1331141cc406Sopenharmony_ci	      s->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
1332141cc406Sopenharmony_ci	    }
1333141cc406Sopenharmony_ci	  else
1334141cc406Sopenharmony_ci	    {
1335141cc406Sopenharmony_ci	      s->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1336141cc406Sopenharmony_ci	      if (s->val[OPT_CUSTOM_GAMMA].w == SANE_TRUE)
1337141cc406Sopenharmony_ci		{
1338141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1339141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1340141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1341141cc406Sopenharmony_ci		  s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1342141cc406Sopenharmony_ci		}
1343141cc406Sopenharmony_ci	    }
1344141cc406Sopenharmony_ci	  myinfo |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1345141cc406Sopenharmony_ci	  break;
1346141cc406Sopenharmony_ci	default:
1347141cc406Sopenharmony_ci	  DBG (2, "sane_control_option: can't set unknown option %d\n",
1348141cc406Sopenharmony_ci	       option);
1349141cc406Sopenharmony_ci	}
1350141cc406Sopenharmony_ci    }
1351141cc406Sopenharmony_ci  else
1352141cc406Sopenharmony_ci    {
1353141cc406Sopenharmony_ci      DBG (2, "sane_control_option: unknown action %d for option %d\n",
1354141cc406Sopenharmony_ci	   action, option);
1355141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1356141cc406Sopenharmony_ci    }
1357141cc406Sopenharmony_ci  if (info)
1358141cc406Sopenharmony_ci    *info = myinfo;
1359141cc406Sopenharmony_ci
1360141cc406Sopenharmony_ci  DBG (5, "sane_control_option: exit\n");
1361141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1362141cc406Sopenharmony_ci}
1363141cc406Sopenharmony_ci
1364141cc406Sopenharmony_ciSANE_Status
1365141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
1366141cc406Sopenharmony_ci{
1367141cc406Sopenharmony_ci  Mustek_Usb_Scanner *s = handle;
1368141cc406Sopenharmony_ci  SANE_Status status;
1369141cc406Sopenharmony_ci
1370141cc406Sopenharmony_ci  DBG (5, "sane_get_parameters: start\n");
1371141cc406Sopenharmony_ci
1372141cc406Sopenharmony_ci  RIE (calc_parameters (s));
1373141cc406Sopenharmony_ci  if (params)
1374141cc406Sopenharmony_ci    *params = s->params;
1375141cc406Sopenharmony_ci
1376141cc406Sopenharmony_ci  DBG (5, "sane_get_parameters: exit\n");
1377141cc406Sopenharmony_ci
1378141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1379141cc406Sopenharmony_ci}
1380141cc406Sopenharmony_ci
1381141cc406Sopenharmony_ciSANE_Status
1382141cc406Sopenharmony_cisane_start (SANE_Handle handle)
1383141cc406Sopenharmony_ci{
1384141cc406Sopenharmony_ci  Mustek_Usb_Scanner *s = handle;
1385141cc406Sopenharmony_ci  SANE_Status status;
1386141cc406Sopenharmony_ci  SANE_String val;
1387141cc406Sopenharmony_ci  Colormode color_mode;
1388141cc406Sopenharmony_ci  SANE_Word dpi, x, y, width, height;
1389141cc406Sopenharmony_ci
1390141cc406Sopenharmony_ci  DBG (5, "sane_start: start\n");
1391141cc406Sopenharmony_ci
1392141cc406Sopenharmony_ci  /* First make sure we have a current parameter set.  Some of the
1393141cc406Sopenharmony_ci     parameters will be overwritten below, but that's OK.  */
1394141cc406Sopenharmony_ci
1395141cc406Sopenharmony_ci  s->total_bytes = 0;
1396141cc406Sopenharmony_ci  s->total_lines = 0;
1397141cc406Sopenharmony_ci  RIE (calc_parameters (s));
1398141cc406Sopenharmony_ci
1399141cc406Sopenharmony_ci  if (s->width_dots <= 0)
1400141cc406Sopenharmony_ci    {
1401141cc406Sopenharmony_ci      DBG (0, "sane_start: top left x > bottom right x --- exiting\n");
1402141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1403141cc406Sopenharmony_ci    }
1404141cc406Sopenharmony_ci  if (s->height_dots <= 0)
1405141cc406Sopenharmony_ci    {
1406141cc406Sopenharmony_ci      DBG (0, "sane_start: top left y > bottom right y --- exiting\n");
1407141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1408141cc406Sopenharmony_ci    }
1409141cc406Sopenharmony_ci
1410141cc406Sopenharmony_ci
1411141cc406Sopenharmony_ci  val = s->val[OPT_MODE].s;
1412141cc406Sopenharmony_ci  if (!strcmp (val, SANE_VALUE_SCAN_MODE_LINEART))
1413141cc406Sopenharmony_ci    color_mode = GRAY8;
1414141cc406Sopenharmony_ci  else if (!strcmp (val, SANE_VALUE_SCAN_MODE_GRAY))
1415141cc406Sopenharmony_ci    color_mode = GRAY8;
1416141cc406Sopenharmony_ci  else				/* Color */
1417141cc406Sopenharmony_ci    color_mode = RGB24;
1418141cc406Sopenharmony_ci
1419141cc406Sopenharmony_ci  dpi = SANE_UNFIX (s->val[OPT_RESOLUTION].w);
1420141cc406Sopenharmony_ci  x = s->tl_x_dots;
1421141cc406Sopenharmony_ci  y = s->tl_y_dots;
1422141cc406Sopenharmony_ci  width = s->width_dots;
1423141cc406Sopenharmony_ci  height = s->height_dots;
1424141cc406Sopenharmony_ci
1425141cc406Sopenharmony_ci  if (!s->hw->is_prepared)
1426141cc406Sopenharmony_ci    {
1427141cc406Sopenharmony_ci      RIE (usb_high_scan_prepare (s->hw));
1428141cc406Sopenharmony_ci      RIE (usb_high_scan_reset (s->hw));
1429141cc406Sopenharmony_ci    }
1430141cc406Sopenharmony_ci  RIE (usb_high_scan_set_threshold (s->hw, 128));
1431141cc406Sopenharmony_ci  RIE (usb_high_scan_embed_gamma (s->hw, NULL));
1432141cc406Sopenharmony_ci  RIE (usb_high_scan_suggest_parameters (s->hw, dpi, x, y, width, height,
1433141cc406Sopenharmony_ci					 color_mode));
1434141cc406Sopenharmony_ci  RIE (usb_high_scan_setup_scan (s->hw, s->hw->scan_mode, s->hw->x_dpi,
1435141cc406Sopenharmony_ci				 s->hw->y_dpi, 0, s->hw->x, s->hw->y,
1436141cc406Sopenharmony_ci				 s->hw->width));
1437141cc406Sopenharmony_ci
1438141cc406Sopenharmony_ci  DBG (3, "sane_start: wanted: dpi=%d, x=%d, y=%d, width=%d, height=%d, "
1439141cc406Sopenharmony_ci       "scan_mode=%d\n", dpi, x, y, width, height, color_mode);
1440141cc406Sopenharmony_ci  DBG (3, "sane_start: got: x_dpi=%d, y_dpi=%d, x=%d, y=%d, width=%d, "
1441141cc406Sopenharmony_ci       "height=%d, scan_mode=%d\n", s->hw->x_dpi, s->hw->y_dpi, s->hw->x,
1442141cc406Sopenharmony_ci       s->hw->y, s->hw->width, s->hw->height, s->hw->scan_mode);
1443141cc406Sopenharmony_ci
1444141cc406Sopenharmony_ci  s->scanning = SANE_TRUE;
1445141cc406Sopenharmony_ci  s->read_rows = s->hw->height;
1446141cc406Sopenharmony_ci  s->hw->line_switch = s->hw->height;
1447141cc406Sopenharmony_ci  s->hw->line_offset = 0;
1448141cc406Sopenharmony_ci  s->hw->scan_buffer_len = 0;
1449141cc406Sopenharmony_ci
1450141cc406Sopenharmony_ci  DBG (5, "sane_start: exit\n");
1451141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1452141cc406Sopenharmony_ci}
1453141cc406Sopenharmony_ci
1454141cc406Sopenharmony_ciSANE_Status
1455141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
1456141cc406Sopenharmony_ci	   SANE_Int * len)
1457141cc406Sopenharmony_ci{
1458141cc406Sopenharmony_ci  Mustek_Usb_Scanner *s = handle;
1459141cc406Sopenharmony_ci  SANE_Word lines_to_read, lines_read;
1460141cc406Sopenharmony_ci  SANE_Status status;
1461141cc406Sopenharmony_ci
1462141cc406Sopenharmony_ci  DBG (5, "sane_read: start\n");
1463141cc406Sopenharmony_ci
1464141cc406Sopenharmony_ci  if (!s)
1465141cc406Sopenharmony_ci    {
1466141cc406Sopenharmony_ci      DBG (1, "sane_read: handle is null!\n");
1467141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1468141cc406Sopenharmony_ci    }
1469141cc406Sopenharmony_ci
1470141cc406Sopenharmony_ci  if (!buf)
1471141cc406Sopenharmony_ci    {
1472141cc406Sopenharmony_ci      DBG (1, "sane_read: buf is null!\n");
1473141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1474141cc406Sopenharmony_ci    }
1475141cc406Sopenharmony_ci
1476141cc406Sopenharmony_ci  if (!len)
1477141cc406Sopenharmony_ci    {
1478141cc406Sopenharmony_ci      DBG (1, "sane_read: len is null!\n");
1479141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1480141cc406Sopenharmony_ci    }
1481141cc406Sopenharmony_ci
1482141cc406Sopenharmony_ci  *len = 0;
1483141cc406Sopenharmony_ci
1484141cc406Sopenharmony_ci  if (!s->scanning)
1485141cc406Sopenharmony_ci    {
1486141cc406Sopenharmony_ci      DBG (3, "sane_read: scan was cancelled, is over or has not been "
1487141cc406Sopenharmony_ci	   "initiated yet\n");
1488141cc406Sopenharmony_ci      return SANE_STATUS_CANCELLED;
1489141cc406Sopenharmony_ci    }
1490141cc406Sopenharmony_ci
1491141cc406Sopenharmony_ci  if (s->hw->scan_buffer_len == 0)
1492141cc406Sopenharmony_ci    {
1493141cc406Sopenharmony_ci      if (s->read_rows > 0)
1494141cc406Sopenharmony_ci	{
1495141cc406Sopenharmony_ci	  lines_to_read = SCAN_BUFFER_SIZE / (s->hw->width * s->hw->bpp / 8);
1496141cc406Sopenharmony_ci	  if (lines_to_read > s->read_rows)
1497141cc406Sopenharmony_ci	    lines_to_read = s->read_rows;
1498141cc406Sopenharmony_ci	  s->hw->temp_buffer_start = s->hw->temp_buffer;
1499141cc406Sopenharmony_ci	  s->hw->temp_buffer_len = (s->hw->width * s->hw->bpp / 8)
1500141cc406Sopenharmony_ci	    * lines_to_read;
1501141cc406Sopenharmony_ci	  DBG (4, "sane_read: reading %d source lines\n", lines_to_read);
1502141cc406Sopenharmony_ci	  RIE (usb_high_scan_get_rows (s->hw, s->hw->temp_buffer,
1503141cc406Sopenharmony_ci				       lines_to_read, SANE_FALSE));
1504141cc406Sopenharmony_ci	  RIE (fit_lines (s, s->hw->temp_buffer, s->hw->scan_buffer,
1505141cc406Sopenharmony_ci			  lines_to_read, &lines_read));
1506141cc406Sopenharmony_ci	  s->read_rows -= lines_to_read;
1507141cc406Sopenharmony_ci	  if ((s->total_lines + lines_read) > s->height_dots)
1508141cc406Sopenharmony_ci	    lines_read = s->height_dots - s->total_lines;
1509141cc406Sopenharmony_ci	  s->total_lines += lines_read;
1510141cc406Sopenharmony_ci	  DBG (4, "sane_read: %d destination lines, %d total\n",
1511141cc406Sopenharmony_ci	       lines_read, s->total_lines);
1512141cc406Sopenharmony_ci	  s->hw->scan_buffer_start = s->hw->scan_buffer;
1513141cc406Sopenharmony_ci	  s->hw->scan_buffer_len = (s->width_dots * s->bpp / 8) * lines_read;
1514141cc406Sopenharmony_ci	}
1515141cc406Sopenharmony_ci      else
1516141cc406Sopenharmony_ci	{
1517141cc406Sopenharmony_ci	  DBG (4, "sane_read: scan finished -- exit\n");
1518141cc406Sopenharmony_ci	  return SANE_STATUS_EOF;
1519141cc406Sopenharmony_ci	}
1520141cc406Sopenharmony_ci    }
1521141cc406Sopenharmony_ci  if (s->hw->scan_buffer_len == 0)
1522141cc406Sopenharmony_ci    {
1523141cc406Sopenharmony_ci      DBG (4, "sane_read: scan finished -- exit\n");
1524141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
1525141cc406Sopenharmony_ci    }
1526141cc406Sopenharmony_ci
1527141cc406Sopenharmony_ci  *len = MIN (max_len, (SANE_Int) s->hw->scan_buffer_len);
1528141cc406Sopenharmony_ci  memcpy (buf, s->hw->scan_buffer_start, *len);
1529141cc406Sopenharmony_ci  DBG (4, "sane_read: exit, read %d bytes from scan_buffer; "
1530141cc406Sopenharmony_ci       "%ld bytes remaining\n", *len,
1531141cc406Sopenharmony_ci       (long int) (s->hw->scan_buffer_len - *len));
1532141cc406Sopenharmony_ci  s->hw->scan_buffer_len -= (*len);
1533141cc406Sopenharmony_ci  s->hw->scan_buffer_start += (*len);
1534141cc406Sopenharmony_ci  s->total_bytes += (*len);
1535141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1536141cc406Sopenharmony_ci}
1537141cc406Sopenharmony_ci
1538141cc406Sopenharmony_civoid
1539141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
1540141cc406Sopenharmony_ci{
1541141cc406Sopenharmony_ci  Mustek_Usb_Scanner *s = handle;
1542141cc406Sopenharmony_ci  SANE_Status status;
1543141cc406Sopenharmony_ci
1544141cc406Sopenharmony_ci  DBG (5, "sane_cancel: start\n");
1545141cc406Sopenharmony_ci
1546141cc406Sopenharmony_ci  status = usb_high_scan_stop_scan (s->hw);
1547141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1548141cc406Sopenharmony_ci    DBG (3, "sane_cancel: usb_high_scan_stop_scan returned `%s' for `%s'\n",
1549141cc406Sopenharmony_ci	 sane_strstatus (status), s->hw->name);
1550141cc406Sopenharmony_ci  usb_high_scan_back_home (s->hw);
1551141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1552141cc406Sopenharmony_ci    DBG (3, "sane_cancel: usb_high_scan_back_home returned `%s' for `%s'\n",
1553141cc406Sopenharmony_ci	 sane_strstatus (status), s->hw->name);
1554141cc406Sopenharmony_ci
1555141cc406Sopenharmony_ci  if (s->scanning)
1556141cc406Sopenharmony_ci    {
1557141cc406Sopenharmony_ci      s->scanning = SANE_FALSE;
1558141cc406Sopenharmony_ci      if (s->total_bytes != (s->params.bytes_per_line * s->params.lines))
1559141cc406Sopenharmony_ci	DBG (1, "sane_cancel: warning: scanned %d bytes, expected %d "
1560141cc406Sopenharmony_ci	     "bytes\n", s->total_bytes,
1561141cc406Sopenharmony_ci	     s->params.bytes_per_line * s->params.lines);
1562141cc406Sopenharmony_ci      else
1563141cc406Sopenharmony_ci	DBG (3, "sane_cancel: scan finished, scanned %d bytes\n",
1564141cc406Sopenharmony_ci	     s->total_bytes);
1565141cc406Sopenharmony_ci    }
1566141cc406Sopenharmony_ci  else
1567141cc406Sopenharmony_ci    {
1568141cc406Sopenharmony_ci      DBG (4, "sane_cancel: scan has not been initiated yet, "
1569141cc406Sopenharmony_ci	   "or it is already aborted\n");
1570141cc406Sopenharmony_ci    }
1571141cc406Sopenharmony_ci  DBG (5, "sane_cancel: exit\n");
1572141cc406Sopenharmony_ci  return;
1573141cc406Sopenharmony_ci}
1574141cc406Sopenharmony_ci
1575141cc406Sopenharmony_ciSANE_Status
1576141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
1577141cc406Sopenharmony_ci{
1578141cc406Sopenharmony_ci  Mustek_Usb_Scanner *s = handle;
1579141cc406Sopenharmony_ci
1580141cc406Sopenharmony_ci  DBG (5, "sane_set_io_mode: handle = %p, non_blocking = %s\n",
1581141cc406Sopenharmony_ci       handle, non_blocking == SANE_TRUE ? "true" : "false");
1582141cc406Sopenharmony_ci  if (!s->scanning)
1583141cc406Sopenharmony_ci    {
1584141cc406Sopenharmony_ci      DBG (1, "sane_set_io_mode: not scanning\n");
1585141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1586141cc406Sopenharmony_ci    }
1587141cc406Sopenharmony_ci  if (non_blocking)
1588141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1589141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1590141cc406Sopenharmony_ci}
1591141cc406Sopenharmony_ci
1592141cc406Sopenharmony_ciSANE_Status
1593141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
1594141cc406Sopenharmony_ci{
1595141cc406Sopenharmony_ci  Mustek_Usb_Scanner *s = handle;
1596141cc406Sopenharmony_ci
1597141cc406Sopenharmony_ci  DBG (5, "sane_get_select_fd: handle = %p, fd = %p\n", handle, (void *) fd);
1598141cc406Sopenharmony_ci  if (!s->scanning)
1599141cc406Sopenharmony_ci    {
1600141cc406Sopenharmony_ci      DBG (1, "sane_get_select_fd: not scanning\n");
1601141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1602141cc406Sopenharmony_ci    }
1603141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
1604141cc406Sopenharmony_ci}
1605