1141cc406Sopenharmony_ci/* lexmark.c: SANE backend for Lexmark scanners.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   (C) 2003-2004 Lexmark International, Inc. (Original Source code)
4141cc406Sopenharmony_ci   (C) 2005 Fred Odendaal
5141cc406Sopenharmony_ci   (C) 2006-2013 Stéphane Voltz <stef.dev@free.fr>
6141cc406Sopenharmony_ci   (C) 2010 "Torsten Houwaart" <ToHo@gmx.de> X74 support
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   **************************************************************************/
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_ci#include "lexmark.h"
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci#define LEXMARK_CONFIG_FILE "lexmark.conf"
49141cc406Sopenharmony_ci#define BUILD 32
50141cc406Sopenharmony_ci#define MAX_OPTION_STRING_SIZE 255
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_cistatic Lexmark_Device *first_lexmark_device = 0;
53141cc406Sopenharmony_cistatic SANE_Int num_lexmark_device = 0;
54141cc406Sopenharmony_cistatic const SANE_Device **sane_device_list = NULL;
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci/* Program globals F.O - Should this be per device?*/
57141cc406Sopenharmony_cistatic SANE_Bool initialized = SANE_FALSE;
58141cc406Sopenharmony_ci
59141cc406Sopenharmony_cistatic SANE_String_Const mode_list[] = {
60141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_COLOR,
61141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_GRAY,
62141cc406Sopenharmony_ci  SANE_VALUE_SCAN_MODE_LINEART,
63141cc406Sopenharmony_ci  NULL
64141cc406Sopenharmony_ci};
65141cc406Sopenharmony_ci
66141cc406Sopenharmony_ci/* possible resolutions are: 75x75, 150x150, 300x300, 600x600, 600x1200 */
67141cc406Sopenharmony_ci
68141cc406Sopenharmony_cistatic SANE_Int x1100_dpi_list[] = {
69141cc406Sopenharmony_ci  5, 75, 150, 300, 600, 1200
70141cc406Sopenharmony_ci};
71141cc406Sopenharmony_ci
72141cc406Sopenharmony_cistatic SANE_Int a920_dpi_list[] = {
73141cc406Sopenharmony_ci  4, 75, 150, 300, 600
74141cc406Sopenharmony_ci};
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_cistatic SANE_Int x1200_dpi_list[] = {
77141cc406Sopenharmony_ci  4, 75, 150, 300, 600
78141cc406Sopenharmony_ci};
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_cistatic SANE_Int x74_dpi_list[] = {
81141cc406Sopenharmony_ci  75, 150, 300, 600
82141cc406Sopenharmony_ci};
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_cistatic SANE_Range threshold_range = {
85141cc406Sopenharmony_ci  SANE_FIX (0.0),		/* minimum */
86141cc406Sopenharmony_ci  SANE_FIX (100.0),		/* maximum */
87141cc406Sopenharmony_ci  SANE_FIX (1.0)		/* quantization */
88141cc406Sopenharmony_ci};
89141cc406Sopenharmony_ci
90141cc406Sopenharmony_cistatic const SANE_Range gain_range = {
91141cc406Sopenharmony_ci  0,				/* minimum */
92141cc406Sopenharmony_ci  31,				/* maximum */
93141cc406Sopenharmony_ci  0				/* quantization */
94141cc406Sopenharmony_ci};
95141cc406Sopenharmony_ci
96141cc406Sopenharmony_ci/* for now known models (2 ...) have the same scan window geometry.
97141cc406Sopenharmony_ci   coordinates are expressed in pixels, with a quantization factor of
98141cc406Sopenharmony_ci   8 to have 'even' coordinates at 75 dpi */
99141cc406Sopenharmony_cistatic SANE_Range x_range = {
100141cc406Sopenharmony_ci  0,				/* minimum */
101141cc406Sopenharmony_ci  5104,				/* maximum */
102141cc406Sopenharmony_ci  16				/* quantization : 16 is required so we
103141cc406Sopenharmony_ci				   never have an odd width */
104141cc406Sopenharmony_ci};
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_cistatic SANE_Range y_range = {
107141cc406Sopenharmony_ci  0,				/* minimum */
108141cc406Sopenharmony_ci  6848,				/* maximum */
109141cc406Sopenharmony_ci  /* 7032, for X74 */
110141cc406Sopenharmony_ci  8				/* quantization */
111141cc406Sopenharmony_ci};
112141cc406Sopenharmony_ci
113141cc406Sopenharmony_ci/* static functions */
114141cc406Sopenharmony_cistatic SANE_Status init_options (Lexmark_Device * lexmark_device);
115141cc406Sopenharmony_cistatic SANE_Status attachLexmark (SANE_String_Const devname);
116141cc406Sopenharmony_ci
117141cc406Sopenharmony_ciSANE_Status
118141cc406Sopenharmony_ciinit_options (Lexmark_Device * dev)
119141cc406Sopenharmony_ci{
120141cc406Sopenharmony_ci
121141cc406Sopenharmony_ci  SANE_Option_Descriptor *od;
122141cc406Sopenharmony_ci
123141cc406Sopenharmony_ci  DBG (2, "init_options: dev = %p\n", (void *) dev);
124141cc406Sopenharmony_ci
125141cc406Sopenharmony_ci  /* number of options */
126141cc406Sopenharmony_ci  od = &(dev->opt[OPT_NUM_OPTS]);
127141cc406Sopenharmony_ci  od->name = SANE_NAME_NUM_OPTIONS;
128141cc406Sopenharmony_ci  od->title = SANE_TITLE_NUM_OPTIONS;
129141cc406Sopenharmony_ci  od->desc = SANE_DESC_NUM_OPTIONS;
130141cc406Sopenharmony_ci  od->type = SANE_TYPE_INT;
131141cc406Sopenharmony_ci  od->unit = SANE_UNIT_NONE;
132141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
133141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT;
134141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_NONE;
135141cc406Sopenharmony_ci  od->constraint.range = 0;
136141cc406Sopenharmony_ci  dev->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
137141cc406Sopenharmony_ci
138141cc406Sopenharmony_ci  /* mode - sets the scan mode: Color, Gray, or Line Art */
139141cc406Sopenharmony_ci  od = &(dev->opt[OPT_MODE]);
140141cc406Sopenharmony_ci  od->name = SANE_NAME_SCAN_MODE;
141141cc406Sopenharmony_ci  od->title = SANE_TITLE_SCAN_MODE;
142141cc406Sopenharmony_ci  od->desc = SANE_DESC_SCAN_MODE;;
143141cc406Sopenharmony_ci  od->type = SANE_TYPE_STRING;
144141cc406Sopenharmony_ci  od->unit = SANE_UNIT_NONE;
145141cc406Sopenharmony_ci  od->size = MAX_OPTION_STRING_SIZE;
146141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
147141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_STRING_LIST;
148141cc406Sopenharmony_ci  od->constraint.string_list = mode_list;
149141cc406Sopenharmony_ci  dev->val[OPT_MODE].s = malloc (od->size);
150141cc406Sopenharmony_ci  if (!dev->val[OPT_MODE].s)
151141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
152141cc406Sopenharmony_ci  strcpy (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR);
153141cc406Sopenharmony_ci
154141cc406Sopenharmony_ci  /* resolution */
155141cc406Sopenharmony_ci  od = &(dev->opt[OPT_RESOLUTION]);
156141cc406Sopenharmony_ci  od->name = SANE_NAME_SCAN_RESOLUTION;
157141cc406Sopenharmony_ci  od->title = SANE_TITLE_SCAN_RESOLUTION;
158141cc406Sopenharmony_ci  od->desc = SANE_DESC_SCAN_RESOLUTION;
159141cc406Sopenharmony_ci  od->type = SANE_TYPE_INT;
160141cc406Sopenharmony_ci  od->unit = SANE_UNIT_DPI;
161141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
162141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
163141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_WORD_LIST;
164141cc406Sopenharmony_ci  switch (dev->model.sensor_type)
165141cc406Sopenharmony_ci    {
166141cc406Sopenharmony_ci    case X1100_2C_SENSOR:
167141cc406Sopenharmony_ci    case A920_SENSOR:
168141cc406Sopenharmony_ci      od->constraint.word_list = a920_dpi_list;
169141cc406Sopenharmony_ci      break;
170141cc406Sopenharmony_ci    case X1100_B2_SENSOR:
171141cc406Sopenharmony_ci      od->constraint.word_list = x1100_dpi_list;
172141cc406Sopenharmony_ci      break;
173141cc406Sopenharmony_ci    case X1200_SENSOR:
174141cc406Sopenharmony_ci    case X1200_USB2_SENSOR:
175141cc406Sopenharmony_ci      od->constraint.word_list = x1200_dpi_list;
176141cc406Sopenharmony_ci      break;
177141cc406Sopenharmony_ci    case X74_SENSOR:
178141cc406Sopenharmony_ci      od->constraint.word_list = x74_dpi_list;
179141cc406Sopenharmony_ci      break;
180141cc406Sopenharmony_ci    }
181141cc406Sopenharmony_ci  dev->val[OPT_RESOLUTION].w = 75;
182141cc406Sopenharmony_ci
183141cc406Sopenharmony_ci  /* preview mode */
184141cc406Sopenharmony_ci  od = &(dev->opt[OPT_PREVIEW]);
185141cc406Sopenharmony_ci  od->name = SANE_NAME_PREVIEW;
186141cc406Sopenharmony_ci  od->title = SANE_TITLE_PREVIEW;
187141cc406Sopenharmony_ci  od->desc = SANE_DESC_PREVIEW;
188141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
189141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
190141cc406Sopenharmony_ci  od->type = SANE_TYPE_BOOL;
191141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_NONE;
192141cc406Sopenharmony_ci  dev->val[OPT_PREVIEW].w = SANE_FALSE;
193141cc406Sopenharmony_ci
194141cc406Sopenharmony_ci  /* "Geometry" group: */
195141cc406Sopenharmony_ci  od = &(dev->opt[OPT_GEOMETRY_GROUP]);
196141cc406Sopenharmony_ci  od->name = "";
197141cc406Sopenharmony_ci  od->title = SANE_I18N ("Geometry");
198141cc406Sopenharmony_ci  od->desc = "";
199141cc406Sopenharmony_ci  od->type = SANE_TYPE_GROUP;
200141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
201141cc406Sopenharmony_ci  od->size = 0;
202141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_NONE;
203141cc406Sopenharmony_ci
204141cc406Sopenharmony_ci  /* top-left x */
205141cc406Sopenharmony_ci  od = &(dev->opt[OPT_TL_X]);
206141cc406Sopenharmony_ci  od->name = SANE_NAME_SCAN_TL_X;
207141cc406Sopenharmony_ci  od->title = SANE_TITLE_SCAN_TL_X;
208141cc406Sopenharmony_ci  od->desc = SANE_DESC_SCAN_TL_X;
209141cc406Sopenharmony_ci  od->type = SANE_TYPE_INT;
210141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
211141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
212141cc406Sopenharmony_ci  od->unit = SANE_UNIT_PIXEL;
213141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_RANGE;
214141cc406Sopenharmony_ci  od->constraint.range = &x_range;
215141cc406Sopenharmony_ci  dev->val[OPT_TL_X].w = 0;
216141cc406Sopenharmony_ci
217141cc406Sopenharmony_ci  /* top-left y */
218141cc406Sopenharmony_ci  od = &(dev->opt[OPT_TL_Y]);
219141cc406Sopenharmony_ci  od->name = SANE_NAME_SCAN_TL_Y;
220141cc406Sopenharmony_ci  od->title = SANE_TITLE_SCAN_TL_Y;
221141cc406Sopenharmony_ci  od->desc = SANE_DESC_SCAN_TL_Y;
222141cc406Sopenharmony_ci  od->type = SANE_TYPE_INT;
223141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
224141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
225141cc406Sopenharmony_ci  od->unit = SANE_UNIT_PIXEL;
226141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_RANGE;
227141cc406Sopenharmony_ci  od->constraint.range = &y_range;
228141cc406Sopenharmony_ci  dev->val[OPT_TL_Y].w = 0;
229141cc406Sopenharmony_ci
230141cc406Sopenharmony_ci  /* bottom-right x */
231141cc406Sopenharmony_ci  od = &(dev->opt[OPT_BR_X]);
232141cc406Sopenharmony_ci  od->name = SANE_NAME_SCAN_BR_X;
233141cc406Sopenharmony_ci  od->title = SANE_TITLE_SCAN_BR_X;
234141cc406Sopenharmony_ci  od->desc = SANE_DESC_SCAN_BR_X;
235141cc406Sopenharmony_ci  od->type = SANE_TYPE_INT;
236141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
237141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
238141cc406Sopenharmony_ci  od->unit = SANE_UNIT_PIXEL;
239141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_RANGE;
240141cc406Sopenharmony_ci  od->constraint.range = &x_range;
241141cc406Sopenharmony_ci  dev->val[OPT_BR_X].w = x_range.max;
242141cc406Sopenharmony_ci
243141cc406Sopenharmony_ci  /* bottom-right y */
244141cc406Sopenharmony_ci  od = &(dev->opt[OPT_BR_Y]);
245141cc406Sopenharmony_ci  od->name = SANE_NAME_SCAN_BR_Y;
246141cc406Sopenharmony_ci  od->title = SANE_TITLE_SCAN_BR_Y;
247141cc406Sopenharmony_ci  od->desc = SANE_DESC_SCAN_BR_Y;
248141cc406Sopenharmony_ci  od->type = SANE_TYPE_INT;
249141cc406Sopenharmony_ci  od->size = sizeof (SANE_Word);
250141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
251141cc406Sopenharmony_ci  od->unit = SANE_UNIT_PIXEL;
252141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_RANGE;
253141cc406Sopenharmony_ci  od->constraint.range = &y_range;
254141cc406Sopenharmony_ci  dev->val[OPT_BR_Y].w = y_range.max;
255141cc406Sopenharmony_ci
256141cc406Sopenharmony_ci  /* threshold */
257141cc406Sopenharmony_ci  od = &(dev->opt[OPT_THRESHOLD]);
258141cc406Sopenharmony_ci  od->name = SANE_NAME_THRESHOLD;
259141cc406Sopenharmony_ci  od->title = SANE_TITLE_THRESHOLD;
260141cc406Sopenharmony_ci  od->desc = SANE_DESC_THRESHOLD;
261141cc406Sopenharmony_ci  od->type = SANE_TYPE_FIXED;
262141cc406Sopenharmony_ci  od->unit = SANE_UNIT_PERCENT;
263141cc406Sopenharmony_ci  od->size = sizeof (SANE_Fixed);
264141cc406Sopenharmony_ci  od->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE;
265141cc406Sopenharmony_ci  od->constraint_type = SANE_CONSTRAINT_RANGE;
266141cc406Sopenharmony_ci  od->constraint.range = &threshold_range;
267141cc406Sopenharmony_ci  dev->val[OPT_THRESHOLD].w = SANE_FIX (50.0);
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci  /*  gain group */
270141cc406Sopenharmony_ci  dev->opt[OPT_MANUAL_GAIN].name = "manual-channel-gain";
271141cc406Sopenharmony_ci  dev->opt[OPT_MANUAL_GAIN].title = SANE_I18N ("Gain");
272141cc406Sopenharmony_ci  dev->opt[OPT_MANUAL_GAIN].desc = SANE_I18N ("Color channels gain settings");
273141cc406Sopenharmony_ci  dev->opt[OPT_MANUAL_GAIN].type = SANE_TYPE_BOOL;
274141cc406Sopenharmony_ci  dev->opt[OPT_MANUAL_GAIN].cap =
275141cc406Sopenharmony_ci    SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED;
276141cc406Sopenharmony_ci  dev->opt[OPT_MANUAL_GAIN].size = sizeof (SANE_Bool);
277141cc406Sopenharmony_ci  dev->val[OPT_MANUAL_GAIN].w = SANE_FALSE;
278141cc406Sopenharmony_ci
279141cc406Sopenharmony_ci  /* gray gain */
280141cc406Sopenharmony_ci  dev->opt[OPT_GRAY_GAIN].name = "gray-gain";
281141cc406Sopenharmony_ci  dev->opt[OPT_GRAY_GAIN].title = SANE_I18N ("Gray gain");
282141cc406Sopenharmony_ci  dev->opt[OPT_GRAY_GAIN].desc = SANE_I18N ("Sets gray channel gain");
283141cc406Sopenharmony_ci  dev->opt[OPT_GRAY_GAIN].type = SANE_TYPE_INT;
284141cc406Sopenharmony_ci  dev->opt[OPT_GRAY_GAIN].cap =
285141cc406Sopenharmony_ci    SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE |
286141cc406Sopenharmony_ci    SANE_CAP_ADVANCED;
287141cc406Sopenharmony_ci  dev->opt[OPT_GRAY_GAIN].unit = SANE_UNIT_NONE;
288141cc406Sopenharmony_ci  dev->opt[OPT_GRAY_GAIN].size = sizeof (SANE_Int);
289141cc406Sopenharmony_ci  dev->opt[OPT_GRAY_GAIN].constraint_type = SANE_CONSTRAINT_RANGE;
290141cc406Sopenharmony_ci  dev->opt[OPT_GRAY_GAIN].constraint.range = &gain_range;
291141cc406Sopenharmony_ci  dev->val[OPT_GRAY_GAIN].w = 10;
292141cc406Sopenharmony_ci
293141cc406Sopenharmony_ci  /* red gain */
294141cc406Sopenharmony_ci  dev->opt[OPT_RED_GAIN].name = "red-gain";
295141cc406Sopenharmony_ci  dev->opt[OPT_RED_GAIN].title = SANE_I18N ("Red gain");
296141cc406Sopenharmony_ci  dev->opt[OPT_RED_GAIN].desc = SANE_I18N ("Sets red channel gain");
297141cc406Sopenharmony_ci  dev->opt[OPT_RED_GAIN].type = SANE_TYPE_INT;
298141cc406Sopenharmony_ci  dev->opt[OPT_RED_GAIN].cap =
299141cc406Sopenharmony_ci    SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE |
300141cc406Sopenharmony_ci    SANE_CAP_ADVANCED;
301141cc406Sopenharmony_ci  dev->opt[OPT_RED_GAIN].unit = SANE_UNIT_NONE;
302141cc406Sopenharmony_ci  dev->opt[OPT_RED_GAIN].size = sizeof (SANE_Int);
303141cc406Sopenharmony_ci  dev->opt[OPT_RED_GAIN].constraint_type = SANE_CONSTRAINT_RANGE;
304141cc406Sopenharmony_ci  dev->opt[OPT_RED_GAIN].constraint.range = &gain_range;
305141cc406Sopenharmony_ci  dev->val[OPT_RED_GAIN].w = 10;
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci  /* green gain */
308141cc406Sopenharmony_ci  dev->opt[OPT_GREEN_GAIN].name = "green-gain";
309141cc406Sopenharmony_ci  dev->opt[OPT_GREEN_GAIN].title = SANE_I18N ("Green gain");
310141cc406Sopenharmony_ci  dev->opt[OPT_GREEN_GAIN].desc = SANE_I18N ("Sets green channel gain");
311141cc406Sopenharmony_ci  dev->opt[OPT_GREEN_GAIN].type = SANE_TYPE_INT;
312141cc406Sopenharmony_ci  dev->opt[OPT_GREEN_GAIN].cap =
313141cc406Sopenharmony_ci    SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE |
314141cc406Sopenharmony_ci    SANE_CAP_ADVANCED;
315141cc406Sopenharmony_ci  dev->opt[OPT_GREEN_GAIN].unit = SANE_UNIT_NONE;
316141cc406Sopenharmony_ci  dev->opt[OPT_GREEN_GAIN].size = sizeof (SANE_Int);
317141cc406Sopenharmony_ci  dev->opt[OPT_GREEN_GAIN].constraint_type = SANE_CONSTRAINT_RANGE;
318141cc406Sopenharmony_ci  dev->opt[OPT_GREEN_GAIN].constraint.range = &gain_range;
319141cc406Sopenharmony_ci  dev->val[OPT_GREEN_GAIN].w = 10;
320141cc406Sopenharmony_ci
321141cc406Sopenharmony_ci  /* blue gain */
322141cc406Sopenharmony_ci  dev->opt[OPT_BLUE_GAIN].name = "blue-gain";
323141cc406Sopenharmony_ci  dev->opt[OPT_BLUE_GAIN].title = SANE_I18N ("Blue gain");
324141cc406Sopenharmony_ci  dev->opt[OPT_BLUE_GAIN].desc = SANE_I18N ("Sets blue channel gain");
325141cc406Sopenharmony_ci  dev->opt[OPT_BLUE_GAIN].type = SANE_TYPE_INT;
326141cc406Sopenharmony_ci  dev->opt[OPT_BLUE_GAIN].cap =
327141cc406Sopenharmony_ci    SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE |
328141cc406Sopenharmony_ci    SANE_CAP_ADVANCED;
329141cc406Sopenharmony_ci  dev->opt[OPT_BLUE_GAIN].unit = SANE_UNIT_NONE;
330141cc406Sopenharmony_ci  dev->opt[OPT_BLUE_GAIN].size = sizeof (SANE_Int);
331141cc406Sopenharmony_ci  dev->opt[OPT_BLUE_GAIN].constraint_type = SANE_CONSTRAINT_RANGE;
332141cc406Sopenharmony_ci  dev->opt[OPT_BLUE_GAIN].constraint.range = &gain_range;
333141cc406Sopenharmony_ci  dev->val[OPT_BLUE_GAIN].w = 10;
334141cc406Sopenharmony_ci
335141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
336141cc406Sopenharmony_ci}
337141cc406Sopenharmony_ci
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci/***************************** SANE API ****************************/
340141cc406Sopenharmony_ci
341141cc406Sopenharmony_ciSANE_Status
342141cc406Sopenharmony_ciattachLexmark (SANE_String_Const devname)
343141cc406Sopenharmony_ci{
344141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device;
345141cc406Sopenharmony_ci  SANE_Int dn, vendor, product, variant;
346141cc406Sopenharmony_ci  SANE_Status status;
347141cc406Sopenharmony_ci
348141cc406Sopenharmony_ci  DBG (2, "attachLexmark: devname=%s\n", devname);
349141cc406Sopenharmony_ci
350141cc406Sopenharmony_ci  for (lexmark_device = first_lexmark_device; lexmark_device;
351141cc406Sopenharmony_ci       lexmark_device = lexmark_device->next)
352141cc406Sopenharmony_ci    {
353141cc406Sopenharmony_ci      /* already attached devices */
354141cc406Sopenharmony_ci      if (strcmp (lexmark_device->sane.name, devname) == 0)
355141cc406Sopenharmony_ci      {
356141cc406Sopenharmony_ci        lexmark_device->missing = SANE_FALSE;
357141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
358141cc406Sopenharmony_ci      }
359141cc406Sopenharmony_ci    }
360141cc406Sopenharmony_ci
361141cc406Sopenharmony_ci  lexmark_device = (Lexmark_Device *) malloc (sizeof (Lexmark_Device));
362141cc406Sopenharmony_ci  if (lexmark_device == NULL)
363141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci#ifdef FAKE_USB
366141cc406Sopenharmony_ci  status = SANE_STATUS_GOOD;
367141cc406Sopenharmony_ci#else
368141cc406Sopenharmony_ci  status = sanei_usb_open (devname, &dn);
369141cc406Sopenharmony_ci#endif
370141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
371141cc406Sopenharmony_ci    {
372141cc406Sopenharmony_ci      DBG (1, "attachLexmark: couldn't open device `%s': %s\n", devname,
373141cc406Sopenharmony_ci	   sane_strstatus (status));
374141cc406Sopenharmony_ci      return status;
375141cc406Sopenharmony_ci    }
376141cc406Sopenharmony_ci  else
377141cc406Sopenharmony_ci    DBG (2, "attachLexmark: device `%s' successfully opened\n", devname);
378141cc406Sopenharmony_ci
379141cc406Sopenharmony_ci#ifdef FAKE_USB
380141cc406Sopenharmony_ci  status = SANE_STATUS_GOOD;
381141cc406Sopenharmony_ci  /* put the id of the model you want to fake here */
382141cc406Sopenharmony_ci  vendor = 0x043d;
383141cc406Sopenharmony_ci  product = 0x007c;		/* X11xx */
384141cc406Sopenharmony_ci  variant = 0xb2;
385141cc406Sopenharmony_ci#else
386141cc406Sopenharmony_ci  variant = 0;
387141cc406Sopenharmony_ci  status = sanei_usb_get_vendor_product (dn, &vendor, &product);
388141cc406Sopenharmony_ci#endif
389141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
390141cc406Sopenharmony_ci    {
391141cc406Sopenharmony_ci      DBG (1,
392141cc406Sopenharmony_ci	   "attachLexmark: couldn't get vendor and product ids of device `%s': %s\n",
393141cc406Sopenharmony_ci	   devname, sane_strstatus (status));
394141cc406Sopenharmony_ci#ifndef FAKE_USB
395141cc406Sopenharmony_ci      sanei_usb_close (dn);
396141cc406Sopenharmony_ci#endif
397141cc406Sopenharmony_ci      return status;
398141cc406Sopenharmony_ci    }
399141cc406Sopenharmony_ci#ifndef FAKE_USB
400141cc406Sopenharmony_ci  sanei_usb_close (dn);
401141cc406Sopenharmony_ci#endif
402141cc406Sopenharmony_ci
403141cc406Sopenharmony_ci  DBG (2, "attachLexmark: testing device `%s': 0x%04x:0x%04x, variant=%d\n",
404141cc406Sopenharmony_ci       devname, vendor, product, variant);
405141cc406Sopenharmony_ci  if (sanei_lexmark_low_assign_model (lexmark_device,
406141cc406Sopenharmony_ci				      devname,
407141cc406Sopenharmony_ci				      vendor,
408141cc406Sopenharmony_ci				      product, variant) != SANE_STATUS_GOOD)
409141cc406Sopenharmony_ci    {
410141cc406Sopenharmony_ci      DBG (2, "attachLexmark: unsupported device `%s': 0x%04x:0x%04x\n",
411141cc406Sopenharmony_ci	   devname, vendor, product);
412141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
413141cc406Sopenharmony_ci    }
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci  /* add new device to device list */
416141cc406Sopenharmony_ci
417141cc406Sopenharmony_ci  /* there are two variant of the scanner with the same USB id,
418141cc406Sopenharmony_ci   * so we need to read registers from scanner to detect which one
419141cc406Sopenharmony_ci   * is really connected */
420141cc406Sopenharmony_ci  status = sanei_lexmark_low_open_device (lexmark_device);
421141cc406Sopenharmony_ci  sanei_usb_close (lexmark_device->devnum);
422141cc406Sopenharmony_ci
423141cc406Sopenharmony_ci  /* set up scanner start status */
424141cc406Sopenharmony_ci  sanei_lexmark_low_init (lexmark_device);
425141cc406Sopenharmony_ci
426141cc406Sopenharmony_ci  /* Set the default resolution here */
427141cc406Sopenharmony_ci  lexmark_device->x_dpi = 75;
428141cc406Sopenharmony_ci  lexmark_device->y_dpi = 75;
429141cc406Sopenharmony_ci
430141cc406Sopenharmony_ci  /* Make the pointer to the read buffer null here */
431141cc406Sopenharmony_ci  lexmark_device->read_buffer = NULL;
432141cc406Sopenharmony_ci
433141cc406Sopenharmony_ci  /* Set the default threshold for lineart mode here */
434141cc406Sopenharmony_ci  lexmark_device->threshold = 0x80;
435141cc406Sopenharmony_ci
436141cc406Sopenharmony_ci  lexmark_device->shading_coeff = NULL;
437141cc406Sopenharmony_ci
438141cc406Sopenharmony_ci  /* mark device as present */
439141cc406Sopenharmony_ci  lexmark_device->missing = SANE_FALSE;
440141cc406Sopenharmony_ci
441141cc406Sopenharmony_ci  /* insert it a the start of the chained list */
442141cc406Sopenharmony_ci  lexmark_device->next = first_lexmark_device;
443141cc406Sopenharmony_ci  first_lexmark_device = lexmark_device;
444141cc406Sopenharmony_ci
445141cc406Sopenharmony_ci  num_lexmark_device++;
446141cc406Sopenharmony_ci
447141cc406Sopenharmony_ci  return status;
448141cc406Sopenharmony_ci}
449141cc406Sopenharmony_ci
450141cc406Sopenharmony_ci/** probe for supported lexmark devices
451141cc406Sopenharmony_ci * This function scan usb and try to attached to scanner
452141cc406Sopenharmony_ci * configured in lexmark.conf .
453141cc406Sopenharmony_ci */
454141cc406Sopenharmony_cistatic SANE_Status
455141cc406Sopenharmony_ciprobe_lexmark_devices (void)
456141cc406Sopenharmony_ci{
457141cc406Sopenharmony_ci  FILE *fp;
458141cc406Sopenharmony_ci  SANE_Char line[PATH_MAX];
459141cc406Sopenharmony_ci  const char *lp;
460141cc406Sopenharmony_ci  SANE_Int vendor, product;
461141cc406Sopenharmony_ci  size_t len;
462141cc406Sopenharmony_ci  Lexmark_Device *dev;
463141cc406Sopenharmony_ci
464141cc406Sopenharmony_ci  /* mark already detected devices as missing, during device probe
465141cc406Sopenharmony_ci   * detected devices will clear this flag */
466141cc406Sopenharmony_ci  dev = first_lexmark_device;
467141cc406Sopenharmony_ci  while (dev != NULL)
468141cc406Sopenharmony_ci    {
469141cc406Sopenharmony_ci      dev->missing = SANE_TRUE;
470141cc406Sopenharmony_ci      dev = dev->next;
471141cc406Sopenharmony_ci    }
472141cc406Sopenharmony_ci
473141cc406Sopenharmony_ci  /* open config file, parse option and try to open
474141cc406Sopenharmony_ci   * any device configure in it */
475141cc406Sopenharmony_ci  fp = sanei_config_open (LEXMARK_CONFIG_FILE);
476141cc406Sopenharmony_ci  if (!fp)
477141cc406Sopenharmony_ci    {
478141cc406Sopenharmony_ci      return SANE_STATUS_ACCESS_DENIED;
479141cc406Sopenharmony_ci    }
480141cc406Sopenharmony_ci
481141cc406Sopenharmony_ci  while (sanei_config_read (line, PATH_MAX, fp))
482141cc406Sopenharmony_ci    {
483141cc406Sopenharmony_ci      /* ignore comments */
484141cc406Sopenharmony_ci      if (line[0] == '#')
485141cc406Sopenharmony_ci	continue;
486141cc406Sopenharmony_ci      len = strlen (line);
487141cc406Sopenharmony_ci
488141cc406Sopenharmony_ci      /* delete newline characters at end */
489141cc406Sopenharmony_ci      if (line[len - 1] == '\n')
490141cc406Sopenharmony_ci	line[--len] = '\0';
491141cc406Sopenharmony_ci
492141cc406Sopenharmony_ci      lp = sanei_config_skip_whitespace (line);
493141cc406Sopenharmony_ci      /* skip empty lines */
494141cc406Sopenharmony_ci      if (*lp == 0)
495141cc406Sopenharmony_ci	continue;
496141cc406Sopenharmony_ci
497141cc406Sopenharmony_ci      if (sscanf (lp, "usb %i %i", &vendor, &product) == 2)
498141cc406Sopenharmony_ci	;
499141cc406Sopenharmony_ci      else if (strncmp ("libusb", lp, 6) == 0)
500141cc406Sopenharmony_ci	;
501141cc406Sopenharmony_ci      else if ((strncmp ("usb", lp, 3) == 0) && isspace (lp[3]))
502141cc406Sopenharmony_ci	{
503141cc406Sopenharmony_ci	  lp += 3;
504141cc406Sopenharmony_ci	  lp = sanei_config_skip_whitespace (lp);
505141cc406Sopenharmony_ci	}
506141cc406Sopenharmony_ci      else
507141cc406Sopenharmony_ci	continue;
508141cc406Sopenharmony_ci
509141cc406Sopenharmony_ci#ifdef FAKE_USB
510141cc406Sopenharmony_ci      attachLexmark ("FAKE_USB");
511141cc406Sopenharmony_ci#else
512141cc406Sopenharmony_ci      sanei_usb_attach_matching_devices (lp, attachLexmark);
513141cc406Sopenharmony_ci#endif
514141cc406Sopenharmony_ci    }
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci  fclose (fp);
517141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
518141cc406Sopenharmony_ci}
519141cc406Sopenharmony_ci
520141cc406Sopenharmony_ciSANE_Status
521141cc406Sopenharmony_cisane_init (SANE_Int * version_code,
522141cc406Sopenharmony_ci	   SANE_Auth_Callback __sane_unused__ authorize)
523141cc406Sopenharmony_ci{
524141cc406Sopenharmony_ci  SANE_Status status;
525141cc406Sopenharmony_ci
526141cc406Sopenharmony_ci  DBG_INIT ();
527141cc406Sopenharmony_ci
528141cc406Sopenharmony_ci  DBG (1, "SANE Lexmark backend version %d.%d.%d-devel\n", SANE_CURRENT_MAJOR,
529141cc406Sopenharmony_ci       SANE_CURRENT_MINOR, BUILD);
530141cc406Sopenharmony_ci
531141cc406Sopenharmony_ci  DBG (2, "sane_init: version_code=%p\n", (void *) version_code);
532141cc406Sopenharmony_ci
533141cc406Sopenharmony_ci  if (version_code)
534141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
535141cc406Sopenharmony_ci
536141cc406Sopenharmony_ci#ifndef FAKE_USB
537141cc406Sopenharmony_ci  sanei_usb_init ();
538141cc406Sopenharmony_ci#endif
539141cc406Sopenharmony_ci
540141cc406Sopenharmony_ci  status = probe_lexmark_devices ();
541141cc406Sopenharmony_ci
542141cc406Sopenharmony_ci  if (status == SANE_STATUS_GOOD)
543141cc406Sopenharmony_ci    {
544141cc406Sopenharmony_ci      initialized = SANE_TRUE;
545141cc406Sopenharmony_ci    }
546141cc406Sopenharmony_ci  else
547141cc406Sopenharmony_ci    {
548141cc406Sopenharmony_ci      initialized = SANE_FALSE;
549141cc406Sopenharmony_ci    }
550141cc406Sopenharmony_ci
551141cc406Sopenharmony_ci  return status;
552141cc406Sopenharmony_ci}
553141cc406Sopenharmony_ci
554141cc406Sopenharmony_civoid
555141cc406Sopenharmony_cisane_exit (void)
556141cc406Sopenharmony_ci{
557141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device, *next_lexmark_device;
558141cc406Sopenharmony_ci
559141cc406Sopenharmony_ci  DBG (2, "sane_exit\n");
560141cc406Sopenharmony_ci
561141cc406Sopenharmony_ci  if (!initialized)
562141cc406Sopenharmony_ci    return;
563141cc406Sopenharmony_ci
564141cc406Sopenharmony_ci  for (lexmark_device = first_lexmark_device; lexmark_device;
565141cc406Sopenharmony_ci       lexmark_device = next_lexmark_device)
566141cc406Sopenharmony_ci    {
567141cc406Sopenharmony_ci      next_lexmark_device = lexmark_device->next;
568141cc406Sopenharmony_ci      sanei_lexmark_low_destroy (lexmark_device);
569141cc406Sopenharmony_ci      free (lexmark_device);
570141cc406Sopenharmony_ci    }
571141cc406Sopenharmony_ci
572141cc406Sopenharmony_ci  if (sane_device_list)
573141cc406Sopenharmony_ci    free (sane_device_list);
574141cc406Sopenharmony_ci
575141cc406Sopenharmony_ci  sanei_usb_exit();
576141cc406Sopenharmony_ci  initialized = SANE_FALSE;
577141cc406Sopenharmony_ci
578141cc406Sopenharmony_ci  return;
579141cc406Sopenharmony_ci}
580141cc406Sopenharmony_ci
581141cc406Sopenharmony_ciSANE_Status
582141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
583141cc406Sopenharmony_ci{
584141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device;
585141cc406Sopenharmony_ci  SANE_Int index;
586141cc406Sopenharmony_ci
587141cc406Sopenharmony_ci  DBG (2, "sane_get_devices: device_list=%p, local_only=%d\n",
588141cc406Sopenharmony_ci       (void *) device_list, local_only);
589141cc406Sopenharmony_ci
590141cc406Sopenharmony_ci  /* hot-plug case : detection of newly connected scanners */
591141cc406Sopenharmony_ci  sanei_usb_scan_devices ();
592141cc406Sopenharmony_ci  probe_lexmark_devices ();
593141cc406Sopenharmony_ci
594141cc406Sopenharmony_ci  if (sane_device_list)
595141cc406Sopenharmony_ci    free (sane_device_list);
596141cc406Sopenharmony_ci
597141cc406Sopenharmony_ci  sane_device_list = malloc ((num_lexmark_device + 1) *
598141cc406Sopenharmony_ci			     sizeof (sane_device_list[0]));
599141cc406Sopenharmony_ci
600141cc406Sopenharmony_ci  if (!sane_device_list)
601141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
602141cc406Sopenharmony_ci
603141cc406Sopenharmony_ci  index = 0;
604141cc406Sopenharmony_ci  lexmark_device = first_lexmark_device;
605141cc406Sopenharmony_ci  while (lexmark_device != NULL)
606141cc406Sopenharmony_ci    {
607141cc406Sopenharmony_ci      if (lexmark_device->missing == SANE_FALSE)
608141cc406Sopenharmony_ci	{
609141cc406Sopenharmony_ci	  sane_device_list[index] = &(lexmark_device->sane);
610141cc406Sopenharmony_ci	  index++;
611141cc406Sopenharmony_ci	}
612141cc406Sopenharmony_ci      lexmark_device = lexmark_device->next;
613141cc406Sopenharmony_ci    }
614141cc406Sopenharmony_ci  sane_device_list[index] = 0;
615141cc406Sopenharmony_ci
616141cc406Sopenharmony_ci  *device_list = sane_device_list;
617141cc406Sopenharmony_ci
618141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
619141cc406Sopenharmony_ci}
620141cc406Sopenharmony_ci
621141cc406Sopenharmony_ci
622141cc406Sopenharmony_ci/**
623141cc406Sopenharmony_ci * Open the backend, ie return the struct handle of a detected scanner
624141cc406Sopenharmony_ci * The struct returned is choosne if it matches the name given, which is
625141cc406Sopenharmony_ci * useful when several scanners handled by the backend have been detected.
626141cc406Sopenharmony_ci * However, special case empty string "" and "lexmark" pick the first
627141cc406Sopenharmony_ci * available handle.
628141cc406Sopenharmony_ci */
629141cc406Sopenharmony_ciSANE_Status
630141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
631141cc406Sopenharmony_ci{
632141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device;
633141cc406Sopenharmony_ci  SANE_Status status;
634141cc406Sopenharmony_ci
635141cc406Sopenharmony_ci  DBG (2, "sane_open: devicename=\"%s\", handle=%p\n", devicename,
636141cc406Sopenharmony_ci       (void *) handle);
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci  if (!initialized)
639141cc406Sopenharmony_ci    {
640141cc406Sopenharmony_ci      DBG (2, "sane_open: not initialized\n");
641141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
642141cc406Sopenharmony_ci    }
643141cc406Sopenharmony_ci
644141cc406Sopenharmony_ci  if (!handle)
645141cc406Sopenharmony_ci    {
646141cc406Sopenharmony_ci      DBG (2, "sane_open: no handle\n");
647141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
648141cc406Sopenharmony_ci    }
649141cc406Sopenharmony_ci
650141cc406Sopenharmony_ci  /* walk the linked list of scanner device until there is a match
651141cc406Sopenharmony_ci   * with the device name */
652141cc406Sopenharmony_ci  for (lexmark_device = first_lexmark_device; lexmark_device;
653141cc406Sopenharmony_ci       lexmark_device = lexmark_device->next)
654141cc406Sopenharmony_ci    {
655141cc406Sopenharmony_ci      DBG (2, "sane_open: devname from list: %s\n",
656141cc406Sopenharmony_ci	   lexmark_device->sane.name);
657141cc406Sopenharmony_ci      if (strcmp (devicename, "") == 0
658141cc406Sopenharmony_ci	  || strcmp (devicename, "lexmark") == 0
659141cc406Sopenharmony_ci	  || strcmp (devicename, lexmark_device->sane.name) == 0)
660141cc406Sopenharmony_ci	break;
661141cc406Sopenharmony_ci    }
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci  *handle = lexmark_device;
664141cc406Sopenharmony_ci
665141cc406Sopenharmony_ci  if (!lexmark_device)
666141cc406Sopenharmony_ci    {
667141cc406Sopenharmony_ci      DBG (2, "sane_open: Not a lexmark device\n");
668141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
669141cc406Sopenharmony_ci    }
670141cc406Sopenharmony_ci
671141cc406Sopenharmony_ci  status = init_options (lexmark_device);
672141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
673141cc406Sopenharmony_ci    return status;
674141cc406Sopenharmony_ci
675141cc406Sopenharmony_ci  status = sanei_lexmark_low_open_device (lexmark_device);
676141cc406Sopenharmony_ci  DBG (2, "sane_open: end.\n");
677141cc406Sopenharmony_ci
678141cc406Sopenharmony_ci  return status;
679141cc406Sopenharmony_ci}
680141cc406Sopenharmony_ci
681141cc406Sopenharmony_civoid
682141cc406Sopenharmony_cisane_close (SANE_Handle handle)
683141cc406Sopenharmony_ci{
684141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device;
685141cc406Sopenharmony_ci
686141cc406Sopenharmony_ci  DBG (2, "sane_close: handle=%p\n", (void *) handle);
687141cc406Sopenharmony_ci
688141cc406Sopenharmony_ci  if (!initialized)
689141cc406Sopenharmony_ci    return;
690141cc406Sopenharmony_ci
691141cc406Sopenharmony_ci  for (lexmark_device = first_lexmark_device; lexmark_device;
692141cc406Sopenharmony_ci       lexmark_device = lexmark_device->next)
693141cc406Sopenharmony_ci    {
694141cc406Sopenharmony_ci      if (lexmark_device == handle)
695141cc406Sopenharmony_ci	break;
696141cc406Sopenharmony_ci    }
697141cc406Sopenharmony_ci
698141cc406Sopenharmony_ci  if (!lexmark_device)
699141cc406Sopenharmony_ci    return;
700141cc406Sopenharmony_ci
701141cc406Sopenharmony_ci  sanei_lexmark_low_close_device (lexmark_device);
702141cc406Sopenharmony_ci
703141cc406Sopenharmony_ci  return;
704141cc406Sopenharmony_ci}
705141cc406Sopenharmony_ci
706141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
707141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
708141cc406Sopenharmony_ci{
709141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device;
710141cc406Sopenharmony_ci
711141cc406Sopenharmony_ci  DBG (2, "sane_get_option_descriptor: handle=%p, option = %d\n",
712141cc406Sopenharmony_ci       (void *) handle, option);
713141cc406Sopenharmony_ci
714141cc406Sopenharmony_ci  if (!initialized)
715141cc406Sopenharmony_ci    return NULL;
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci  /* Check for valid option number */
718141cc406Sopenharmony_ci  if ((option < 0) || (option >= NUM_OPTIONS))
719141cc406Sopenharmony_ci    return NULL;
720141cc406Sopenharmony_ci
721141cc406Sopenharmony_ci  for (lexmark_device = first_lexmark_device; lexmark_device;
722141cc406Sopenharmony_ci       lexmark_device = lexmark_device->next)
723141cc406Sopenharmony_ci    {
724141cc406Sopenharmony_ci      if (lexmark_device == handle)
725141cc406Sopenharmony_ci	break;
726141cc406Sopenharmony_ci    }
727141cc406Sopenharmony_ci
728141cc406Sopenharmony_ci  if (!lexmark_device)
729141cc406Sopenharmony_ci    return NULL;
730141cc406Sopenharmony_ci
731141cc406Sopenharmony_ci  if (lexmark_device->opt[option].name)
732141cc406Sopenharmony_ci    {
733141cc406Sopenharmony_ci      DBG (2, "sane_get_option_descriptor: name=%s\n",
734141cc406Sopenharmony_ci	   lexmark_device->opt[option].name);
735141cc406Sopenharmony_ci    }
736141cc406Sopenharmony_ci
737141cc406Sopenharmony_ci  return &(lexmark_device->opt[option]);
738141cc406Sopenharmony_ci}
739141cc406Sopenharmony_ci
740141cc406Sopenharmony_ci/* rebuilds parameters if needed, called each time SANE_INFO_RELOAD_OPTIONS
741141cc406Sopenharmony_ci   is set */
742141cc406Sopenharmony_cistatic void
743141cc406Sopenharmony_cicalc_parameters (Lexmark_Device * lexmark_device)
744141cc406Sopenharmony_ci{
745141cc406Sopenharmony_ci  if (strcmp (lexmark_device->val[OPT_MODE].s,
746141cc406Sopenharmony_ci	      SANE_VALUE_SCAN_MODE_LINEART) == 0)
747141cc406Sopenharmony_ci    {
748141cc406Sopenharmony_ci      lexmark_device->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
749141cc406Sopenharmony_ci    }
750141cc406Sopenharmony_ci  else
751141cc406Sopenharmony_ci    {
752141cc406Sopenharmony_ci      lexmark_device->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
753141cc406Sopenharmony_ci    }
754141cc406Sopenharmony_ci
755141cc406Sopenharmony_ci  /* changing color mode implies changing gain setting */
756141cc406Sopenharmony_ci  if (lexmark_device->val[OPT_MANUAL_GAIN].w == SANE_TRUE)
757141cc406Sopenharmony_ci    {
758141cc406Sopenharmony_ci      if (strcmp (lexmark_device->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR)
759141cc406Sopenharmony_ci	  != 0)
760141cc406Sopenharmony_ci	{
761141cc406Sopenharmony_ci	  lexmark_device->opt[OPT_GRAY_GAIN].cap &= ~SANE_CAP_INACTIVE;
762141cc406Sopenharmony_ci	  lexmark_device->opt[OPT_RED_GAIN].cap |= SANE_CAP_INACTIVE;
763141cc406Sopenharmony_ci	  lexmark_device->opt[OPT_GREEN_GAIN].cap |= SANE_CAP_INACTIVE;
764141cc406Sopenharmony_ci	  lexmark_device->opt[OPT_BLUE_GAIN].cap |= SANE_CAP_INACTIVE;
765141cc406Sopenharmony_ci	}
766141cc406Sopenharmony_ci      else
767141cc406Sopenharmony_ci	{
768141cc406Sopenharmony_ci	  lexmark_device->opt[OPT_GRAY_GAIN].cap |= SANE_CAP_INACTIVE;
769141cc406Sopenharmony_ci	  lexmark_device->opt[OPT_RED_GAIN].cap &= ~SANE_CAP_INACTIVE;
770141cc406Sopenharmony_ci	  lexmark_device->opt[OPT_GREEN_GAIN].cap &= ~SANE_CAP_INACTIVE;
771141cc406Sopenharmony_ci	  lexmark_device->opt[OPT_BLUE_GAIN].cap &= ~SANE_CAP_INACTIVE;
772141cc406Sopenharmony_ci	}
773141cc406Sopenharmony_ci    }
774141cc406Sopenharmony_ci  else
775141cc406Sopenharmony_ci    {
776141cc406Sopenharmony_ci      lexmark_device->opt[OPT_GRAY_GAIN].cap |= SANE_CAP_INACTIVE;
777141cc406Sopenharmony_ci      lexmark_device->opt[OPT_RED_GAIN].cap |= SANE_CAP_INACTIVE;
778141cc406Sopenharmony_ci      lexmark_device->opt[OPT_GREEN_GAIN].cap |= SANE_CAP_INACTIVE;
779141cc406Sopenharmony_ci      lexmark_device->opt[OPT_BLUE_GAIN].cap |= SANE_CAP_INACTIVE;
780141cc406Sopenharmony_ci    }
781141cc406Sopenharmony_ci}
782141cc406Sopenharmony_ci
783141cc406Sopenharmony_ciSANE_Status
784141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action,
785141cc406Sopenharmony_ci		     void *value, SANE_Int * info)
786141cc406Sopenharmony_ci{
787141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device;
788141cc406Sopenharmony_ci  SANE_Status status;
789141cc406Sopenharmony_ci  SANE_Word w;
790141cc406Sopenharmony_ci
791141cc406Sopenharmony_ci  DBG (2, "sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n",
792141cc406Sopenharmony_ci       (void *) handle, option, action, (void *) value, (void *) info);
793141cc406Sopenharmony_ci
794141cc406Sopenharmony_ci  if (!initialized)
795141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
796141cc406Sopenharmony_ci
797141cc406Sopenharmony_ci  for (lexmark_device = first_lexmark_device; lexmark_device;
798141cc406Sopenharmony_ci       lexmark_device = lexmark_device->next)
799141cc406Sopenharmony_ci    {
800141cc406Sopenharmony_ci      if (lexmark_device == handle)
801141cc406Sopenharmony_ci	break;
802141cc406Sopenharmony_ci    }
803141cc406Sopenharmony_ci
804141cc406Sopenharmony_ci  if (!lexmark_device)
805141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
806141cc406Sopenharmony_ci
807141cc406Sopenharmony_ci  if (value == NULL)
808141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
809141cc406Sopenharmony_ci
810141cc406Sopenharmony_ci  if (info != NULL)
811141cc406Sopenharmony_ci    *info = 0;
812141cc406Sopenharmony_ci
813141cc406Sopenharmony_ci  if (option < 0 || option >= NUM_OPTIONS)
814141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
815141cc406Sopenharmony_ci
816141cc406Sopenharmony_ci  if (lexmark_device->opt[option].type == SANE_TYPE_GROUP)
817141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
818141cc406Sopenharmony_ci
819141cc406Sopenharmony_ci  switch (action)
820141cc406Sopenharmony_ci    {
821141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
822141cc406Sopenharmony_ci
823141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (lexmark_device->opt[option].cap))
824141cc406Sopenharmony_ci	return SANE_STATUS_INVAL;
825141cc406Sopenharmony_ci      if (!(lexmark_device->opt[option].cap & SANE_CAP_AUTOMATIC))
826141cc406Sopenharmony_ci	return SANE_STATUS_INVAL;
827141cc406Sopenharmony_ci      break;
828141cc406Sopenharmony_ci
829141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
830141cc406Sopenharmony_ci
831141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (lexmark_device->opt[option].cap))
832141cc406Sopenharmony_ci	return SANE_STATUS_INVAL;
833141cc406Sopenharmony_ci
834141cc406Sopenharmony_ci      /* Make sure boolean values are only TRUE or FALSE */
835141cc406Sopenharmony_ci      if (lexmark_device->opt[option].type == SANE_TYPE_BOOL)
836141cc406Sopenharmony_ci	{
837141cc406Sopenharmony_ci	  if (!
838141cc406Sopenharmony_ci	      ((*(SANE_Bool *) value == SANE_FALSE)
839141cc406Sopenharmony_ci	       || (*(SANE_Bool *) value == SANE_TRUE)))
840141cc406Sopenharmony_ci	    return SANE_STATUS_INVAL;
841141cc406Sopenharmony_ci	}
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci      /* Check range constraints */
844141cc406Sopenharmony_ci      if (lexmark_device->opt[option].constraint_type ==
845141cc406Sopenharmony_ci	  SANE_CONSTRAINT_RANGE)
846141cc406Sopenharmony_ci	{
847141cc406Sopenharmony_ci	  status =
848141cc406Sopenharmony_ci	    sanei_constrain_value (&(lexmark_device->opt[option]), value,
849141cc406Sopenharmony_ci				   info);
850141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
851141cc406Sopenharmony_ci	    {
852141cc406Sopenharmony_ci	      DBG (2, "SANE_CONTROL_OPTION: Bad value for range\n");
853141cc406Sopenharmony_ci	      return SANE_STATUS_INVAL;
854141cc406Sopenharmony_ci	    }
855141cc406Sopenharmony_ci	}
856141cc406Sopenharmony_ci
857141cc406Sopenharmony_ci      switch (option)
858141cc406Sopenharmony_ci	{
859141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
860141cc406Sopenharmony_ci	case OPT_RESOLUTION:
861141cc406Sopenharmony_ci	  lexmark_device->val[option].w = *(SANE_Int *) value;
862141cc406Sopenharmony_ci	  sane_get_parameters (handle, 0);
863141cc406Sopenharmony_ci	  break;
864141cc406Sopenharmony_ci	case OPT_TL_X:
865141cc406Sopenharmony_ci	case OPT_TL_Y:
866141cc406Sopenharmony_ci	case OPT_BR_X:
867141cc406Sopenharmony_ci	case OPT_BR_Y:
868141cc406Sopenharmony_ci	  DBG (2, "Option value set to %d (%s)\n", *(SANE_Word *) value,
869141cc406Sopenharmony_ci	       lexmark_device->opt[option].name);
870141cc406Sopenharmony_ci	  lexmark_device->val[option].w = *(SANE_Word *) value;
871141cc406Sopenharmony_ci	  if (lexmark_device->val[OPT_TL_X].w >
872141cc406Sopenharmony_ci	      lexmark_device->val[OPT_BR_X].w)
873141cc406Sopenharmony_ci	    {
874141cc406Sopenharmony_ci	      w = lexmark_device->val[OPT_TL_X].w;
875141cc406Sopenharmony_ci	      lexmark_device->val[OPT_TL_X].w =
876141cc406Sopenharmony_ci		lexmark_device->val[OPT_BR_X].w;
877141cc406Sopenharmony_ci	      lexmark_device->val[OPT_BR_X].w = w;
878141cc406Sopenharmony_ci	      if (info)
879141cc406Sopenharmony_ci		*info |= SANE_INFO_RELOAD_PARAMS;
880141cc406Sopenharmony_ci	    }
881141cc406Sopenharmony_ci	  if (lexmark_device->val[OPT_TL_Y].w >
882141cc406Sopenharmony_ci	      lexmark_device->val[OPT_BR_Y].w)
883141cc406Sopenharmony_ci	    {
884141cc406Sopenharmony_ci	      w = lexmark_device->val[OPT_TL_Y].w;
885141cc406Sopenharmony_ci	      lexmark_device->val[OPT_TL_Y].w =
886141cc406Sopenharmony_ci		lexmark_device->val[OPT_BR_Y].w;
887141cc406Sopenharmony_ci	      lexmark_device->val[OPT_BR_Y].w = w;
888141cc406Sopenharmony_ci	      if (info)
889141cc406Sopenharmony_ci		*info |= SANE_INFO_RELOAD_PARAMS;
890141cc406Sopenharmony_ci	    }
891141cc406Sopenharmony_ci	  break;
892141cc406Sopenharmony_ci	case OPT_THRESHOLD:
893141cc406Sopenharmony_ci	  lexmark_device->val[option].w = *(SANE_Fixed *) value;
894141cc406Sopenharmony_ci	  lexmark_device->threshold =
895141cc406Sopenharmony_ci	    (0xFF * lexmark_device->val[option].w) / 100;
896141cc406Sopenharmony_ci	  break;
897141cc406Sopenharmony_ci	case OPT_PREVIEW:
898141cc406Sopenharmony_ci	  lexmark_device->val[option].w = *(SANE_Int *) value;
899141cc406Sopenharmony_ci	  if (*(SANE_Word *) value)
900141cc406Sopenharmony_ci	    {
901141cc406Sopenharmony_ci	      lexmark_device->y_dpi = lexmark_device->val[OPT_RESOLUTION].w;
902141cc406Sopenharmony_ci	      lexmark_device->val[OPT_RESOLUTION].w = 75;
903141cc406Sopenharmony_ci	    }
904141cc406Sopenharmony_ci	  else
905141cc406Sopenharmony_ci	    {
906141cc406Sopenharmony_ci	      lexmark_device->val[OPT_RESOLUTION].w = lexmark_device->y_dpi;
907141cc406Sopenharmony_ci	    }
908141cc406Sopenharmony_ci	  if (info)
909141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS;
910141cc406Sopenharmony_ci	  sane_get_parameters (handle, 0);
911141cc406Sopenharmony_ci	  if (info)
912141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
913141cc406Sopenharmony_ci	  break;
914141cc406Sopenharmony_ci	case OPT_GRAY_GAIN:
915141cc406Sopenharmony_ci	case OPT_GREEN_GAIN:
916141cc406Sopenharmony_ci	case OPT_RED_GAIN:
917141cc406Sopenharmony_ci	case OPT_BLUE_GAIN:
918141cc406Sopenharmony_ci	  lexmark_device->val[option].w = *(SANE_Word *) value;
919141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
920141cc406Sopenharmony_ci	  break;
921141cc406Sopenharmony_ci	case OPT_MODE:
922141cc406Sopenharmony_ci	  strcpy (lexmark_device->val[option].s, value);
923141cc406Sopenharmony_ci	  calc_parameters (lexmark_device);
924141cc406Sopenharmony_ci	  if (info)
925141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
926141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
927141cc406Sopenharmony_ci	case OPT_MANUAL_GAIN:
928141cc406Sopenharmony_ci	  w = *(SANE_Word *) value;
929141cc406Sopenharmony_ci
930141cc406Sopenharmony_ci	  if (w == lexmark_device->val[OPT_MANUAL_GAIN].w)
931141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;	/* no change */
932141cc406Sopenharmony_ci
933141cc406Sopenharmony_ci	  lexmark_device->val[OPT_MANUAL_GAIN].w = w;
934141cc406Sopenharmony_ci	  calc_parameters (lexmark_device);
935141cc406Sopenharmony_ci	  if (info)
936141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS;
937141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
938141cc406Sopenharmony_ci	}
939141cc406Sopenharmony_ci
940141cc406Sopenharmony_ci      if (info != NULL)
941141cc406Sopenharmony_ci	*info |= SANE_INFO_RELOAD_PARAMS;
942141cc406Sopenharmony_ci
943141cc406Sopenharmony_ci      break;
944141cc406Sopenharmony_ci
945141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
946141cc406Sopenharmony_ci
947141cc406Sopenharmony_ci      switch (option)
948141cc406Sopenharmony_ci	{
949141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
950141cc406Sopenharmony_ci	case OPT_RESOLUTION:
951141cc406Sopenharmony_ci	case OPT_PREVIEW:
952141cc406Sopenharmony_ci	case OPT_MANUAL_GAIN:
953141cc406Sopenharmony_ci	case OPT_GRAY_GAIN:
954141cc406Sopenharmony_ci	case OPT_GREEN_GAIN:
955141cc406Sopenharmony_ci	case OPT_RED_GAIN:
956141cc406Sopenharmony_ci	case OPT_BLUE_GAIN:
957141cc406Sopenharmony_ci	case OPT_TL_X:
958141cc406Sopenharmony_ci	case OPT_TL_Y:
959141cc406Sopenharmony_ci	case OPT_BR_X:
960141cc406Sopenharmony_ci	case OPT_BR_Y:
961141cc406Sopenharmony_ci	  *(SANE_Word *) value = lexmark_device->val[option].w;
962141cc406Sopenharmony_ci	  DBG (2, "Option value = %d (%s)\n", *(SANE_Word *) value,
963141cc406Sopenharmony_ci	       lexmark_device->opt[option].name);
964141cc406Sopenharmony_ci	  break;
965141cc406Sopenharmony_ci	case OPT_THRESHOLD:
966141cc406Sopenharmony_ci	  *(SANE_Fixed *) value = lexmark_device->val[option].w;
967141cc406Sopenharmony_ci	  DBG (2, "Option value = %f\n", SANE_UNFIX (*(SANE_Fixed *) value));
968141cc406Sopenharmony_ci	  break;
969141cc406Sopenharmony_ci	case OPT_MODE:
970141cc406Sopenharmony_ci	  strcpy (value, lexmark_device->val[option].s);
971141cc406Sopenharmony_ci	  break;
972141cc406Sopenharmony_ci	default:
973141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
974141cc406Sopenharmony_ci	}
975141cc406Sopenharmony_ci      break;
976141cc406Sopenharmony_ci
977141cc406Sopenharmony_ci    default:
978141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
979141cc406Sopenharmony_ci
980141cc406Sopenharmony_ci    }
981141cc406Sopenharmony_ci
982141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
983141cc406Sopenharmony_ci}
984141cc406Sopenharmony_ci
985141cc406Sopenharmony_ci
986141cc406Sopenharmony_ciSANE_Status
987141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
988141cc406Sopenharmony_ci{
989141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device;
990141cc406Sopenharmony_ci  SANE_Parameters *device_params;
991141cc406Sopenharmony_ci  SANE_Int xres, yres, width_px, height_px;
992141cc406Sopenharmony_ci  SANE_Int channels, bitsperchannel;
993141cc406Sopenharmony_ci
994141cc406Sopenharmony_ci  DBG (2, "sane_get_parameters: handle=%p, params=%p\n", (void *) handle,
995141cc406Sopenharmony_ci       (void *) params);
996141cc406Sopenharmony_ci
997141cc406Sopenharmony_ci  if (!initialized)
998141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
999141cc406Sopenharmony_ci
1000141cc406Sopenharmony_ci  for (lexmark_device = first_lexmark_device; lexmark_device;
1001141cc406Sopenharmony_ci       lexmark_device = lexmark_device->next)
1002141cc406Sopenharmony_ci    {
1003141cc406Sopenharmony_ci      if (lexmark_device == handle)
1004141cc406Sopenharmony_ci	break;
1005141cc406Sopenharmony_ci    }
1006141cc406Sopenharmony_ci
1007141cc406Sopenharmony_ci  if (!lexmark_device)
1008141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1009141cc406Sopenharmony_ci
1010141cc406Sopenharmony_ci  yres = lexmark_device->val[OPT_RESOLUTION].w;
1011141cc406Sopenharmony_ci  if (yres == 1200)
1012141cc406Sopenharmony_ci    xres = 600;
1013141cc406Sopenharmony_ci  else
1014141cc406Sopenharmony_ci    xres = yres;
1015141cc406Sopenharmony_ci
1016141cc406Sopenharmony_ci  /* 24 bit colour = 8 bits/channel for each of the RGB channels */
1017141cc406Sopenharmony_ci  channels = 3;
1018141cc406Sopenharmony_ci  bitsperchannel = 8;
1019141cc406Sopenharmony_ci
1020141cc406Sopenharmony_ci  /* If not color there is only 1 channel */
1021141cc406Sopenharmony_ci  if (strcmp (lexmark_device->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR)
1022141cc406Sopenharmony_ci      != 0)
1023141cc406Sopenharmony_ci    {
1024141cc406Sopenharmony_ci      channels = 1;
1025141cc406Sopenharmony_ci      bitsperchannel = 8;
1026141cc406Sopenharmony_ci    }
1027141cc406Sopenharmony_ci
1028141cc406Sopenharmony_ci  /* geometry in pixels */
1029141cc406Sopenharmony_ci  width_px =
1030141cc406Sopenharmony_ci    lexmark_device->val[OPT_BR_X].w - lexmark_device->val[OPT_TL_X].w;
1031141cc406Sopenharmony_ci  height_px =
1032141cc406Sopenharmony_ci    lexmark_device->val[OPT_BR_Y].w - lexmark_device->val[OPT_TL_Y].w;
1033141cc406Sopenharmony_ci  DBG (7, "sane_get_parameters: tl=(%d,%d) br=(%d,%d)\n",
1034141cc406Sopenharmony_ci       lexmark_device->val[OPT_TL_X].w, lexmark_device->val[OPT_TL_Y].w,
1035141cc406Sopenharmony_ci       lexmark_device->val[OPT_BR_X].w, lexmark_device->val[OPT_BR_Y].w);
1036141cc406Sopenharmony_ci
1037141cc406Sopenharmony_ci
1038141cc406Sopenharmony_ci  /* we must tell the front end the bitsperchannel for lineart is really */
1039141cc406Sopenharmony_ci  /* only 1, so it can calculate the correct image size */
1040141cc406Sopenharmony_ci  /* If not color there is only 1 channel */
1041141cc406Sopenharmony_ci  if (strcmp (lexmark_device->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART)
1042141cc406Sopenharmony_ci      == 0)
1043141cc406Sopenharmony_ci    {
1044141cc406Sopenharmony_ci      bitsperchannel = 1;
1045141cc406Sopenharmony_ci    }
1046141cc406Sopenharmony_ci
1047141cc406Sopenharmony_ci  device_params = &(lexmark_device->params);
1048141cc406Sopenharmony_ci  device_params->format = SANE_FRAME_RGB;
1049141cc406Sopenharmony_ci  if (channels == 1)
1050141cc406Sopenharmony_ci    device_params->format = SANE_FRAME_GRAY;
1051141cc406Sopenharmony_ci  device_params->last_frame = SANE_TRUE;
1052141cc406Sopenharmony_ci  device_params->lines = (height_px * yres) / 600;
1053141cc406Sopenharmony_ci  device_params->depth = bitsperchannel;
1054141cc406Sopenharmony_ci  device_params->pixels_per_line = (width_px * xres) / 600;
1055141cc406Sopenharmony_ci  /* we always read an even number of sensor pixels */
1056141cc406Sopenharmony_ci  if (device_params->pixels_per_line & 1)
1057141cc406Sopenharmony_ci    device_params->pixels_per_line++;
1058141cc406Sopenharmony_ci
1059141cc406Sopenharmony_ci  /* data_size is the size transferred from the scanner to the backend */
1060141cc406Sopenharmony_ci  /* therefore bitsperchannel is the same for gray and lineart */
1061141cc406Sopenharmony_ci  /* note: bytes_per_line has been divided by 8 in lineart mode */
1062141cc406Sopenharmony_ci  lexmark_device->data_size =
1063141cc406Sopenharmony_ci    channels * device_params->pixels_per_line * device_params->lines;
1064141cc406Sopenharmony_ci
1065141cc406Sopenharmony_ci  if (bitsperchannel == 1)
1066141cc406Sopenharmony_ci    {
1067141cc406Sopenharmony_ci      device_params->bytes_per_line =
1068141cc406Sopenharmony_ci	(SANE_Int) ((7 + device_params->pixels_per_line) / 8);
1069141cc406Sopenharmony_ci    }
1070141cc406Sopenharmony_ci  else
1071141cc406Sopenharmony_ci    {
1072141cc406Sopenharmony_ci      device_params->bytes_per_line =
1073141cc406Sopenharmony_ci	(SANE_Int) (channels * device_params->pixels_per_line);
1074141cc406Sopenharmony_ci    }
1075141cc406Sopenharmony_ci  DBG (2, "sane_get_parameters: Data size determined as %ld\n",
1076141cc406Sopenharmony_ci       lexmark_device->data_size);
1077141cc406Sopenharmony_ci
1078141cc406Sopenharmony_ci  DBG (2, "sane_get_parameters: \n");
1079141cc406Sopenharmony_ci  if (device_params->format == SANE_FRAME_GRAY)
1080141cc406Sopenharmony_ci    DBG (2, "  format: SANE_FRAME_GRAY\n");
1081141cc406Sopenharmony_ci  else if (device_params->format == SANE_FRAME_RGB)
1082141cc406Sopenharmony_ci    DBG (2, "  format: SANE_FRAME_RGB\n");
1083141cc406Sopenharmony_ci  else
1084141cc406Sopenharmony_ci    DBG (2, "  format: UNKNOWN\n");
1085141cc406Sopenharmony_ci  if (device_params->last_frame == SANE_TRUE)
1086141cc406Sopenharmony_ci    DBG (2, "  last_frame: TRUE\n");
1087141cc406Sopenharmony_ci  else
1088141cc406Sopenharmony_ci    DBG (2, "  last_frame: FALSE\n");
1089141cc406Sopenharmony_ci  DBG (2, "  lines %d\n", device_params->lines);
1090141cc406Sopenharmony_ci  DBG (2, "  depth %d\n", device_params->depth);
1091141cc406Sopenharmony_ci  DBG (2, "  pixels_per_line %d\n", device_params->pixels_per_line);
1092141cc406Sopenharmony_ci  DBG (2, "  bytes_per_line %d\n", device_params->bytes_per_line);
1093141cc406Sopenharmony_ci
1094141cc406Sopenharmony_ci  if (params != 0)
1095141cc406Sopenharmony_ci    {
1096141cc406Sopenharmony_ci      params->format = device_params->format;
1097141cc406Sopenharmony_ci      params->last_frame = device_params->last_frame;
1098141cc406Sopenharmony_ci      params->lines = device_params->lines;
1099141cc406Sopenharmony_ci      params->depth = device_params->depth;
1100141cc406Sopenharmony_ci      params->pixels_per_line = device_params->pixels_per_line;
1101141cc406Sopenharmony_ci      params->bytes_per_line = device_params->bytes_per_line;
1102141cc406Sopenharmony_ci    }
1103141cc406Sopenharmony_ci
1104141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1105141cc406Sopenharmony_ci}
1106141cc406Sopenharmony_ci
1107141cc406Sopenharmony_ciSANE_Status
1108141cc406Sopenharmony_cisane_start (SANE_Handle handle)
1109141cc406Sopenharmony_ci{
1110141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device;
1111141cc406Sopenharmony_ci  SANE_Int offset;
1112141cc406Sopenharmony_ci  SANE_Status status;
1113141cc406Sopenharmony_ci  int resolution;
1114141cc406Sopenharmony_ci
1115141cc406Sopenharmony_ci  DBG (2, "sane_start: handle=%p\n", (void *) handle);
1116141cc406Sopenharmony_ci
1117141cc406Sopenharmony_ci  if (!initialized)
1118141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1119141cc406Sopenharmony_ci
1120141cc406Sopenharmony_ci  for (lexmark_device = first_lexmark_device; lexmark_device;
1121141cc406Sopenharmony_ci       lexmark_device = lexmark_device->next)
1122141cc406Sopenharmony_ci    {
1123141cc406Sopenharmony_ci      if (lexmark_device == handle)
1124141cc406Sopenharmony_ci	break;
1125141cc406Sopenharmony_ci    }
1126141cc406Sopenharmony_ci
1127141cc406Sopenharmony_ci  sane_get_parameters (handle, 0);
1128141cc406Sopenharmony_ci
1129141cc406Sopenharmony_ci  if ((lexmark_device->params.lines == 0) ||
1130141cc406Sopenharmony_ci      (lexmark_device->params.pixels_per_line == 0) ||
1131141cc406Sopenharmony_ci      (lexmark_device->params.bytes_per_line == 0))
1132141cc406Sopenharmony_ci    {
1133141cc406Sopenharmony_ci      DBG (2, "sane_start: \n");
1134141cc406Sopenharmony_ci      DBG (2, "  ERROR: Zero size encountered in:\n");
1135141cc406Sopenharmony_ci      DBG (2,
1136141cc406Sopenharmony_ci	   "         number of lines, bytes per line, or pixels per line\n");
1137141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1138141cc406Sopenharmony_ci    }
1139141cc406Sopenharmony_ci
1140141cc406Sopenharmony_ci  lexmark_device->device_cancelled = SANE_FALSE;
1141141cc406Sopenharmony_ci  lexmark_device->data_ctr = 0;
1142141cc406Sopenharmony_ci  lexmark_device->eof = SANE_FALSE;
1143141cc406Sopenharmony_ci
1144141cc406Sopenharmony_ci
1145141cc406Sopenharmony_ci  /* Need this cancel_ctr to determine how many times sane_cancel is called
1146141cc406Sopenharmony_ci     since it is called more than once. */
1147141cc406Sopenharmony_ci  lexmark_device->cancel_ctr = 0;
1148141cc406Sopenharmony_ci
1149141cc406Sopenharmony_ci  /* Find Home */
1150141cc406Sopenharmony_ci  if (sanei_lexmark_low_search_home_fwd (lexmark_device))
1151141cc406Sopenharmony_ci    {
1152141cc406Sopenharmony_ci      DBG (2, "sane_start: Scan head initially at home position\n");
1153141cc406Sopenharmony_ci    }
1154141cc406Sopenharmony_ci  else
1155141cc406Sopenharmony_ci    {
1156141cc406Sopenharmony_ci      /* We may have been rewound too far, so move forward the distance from
1157141cc406Sopenharmony_ci         the edge to the home position */
1158141cc406Sopenharmony_ci      sanei_lexmark_low_move_fwd (0x01a8, lexmark_device,
1159141cc406Sopenharmony_ci				  lexmark_device->shadow_regs);
1160141cc406Sopenharmony_ci
1161141cc406Sopenharmony_ci      /* Scan backwards until we find home */
1162141cc406Sopenharmony_ci      sanei_lexmark_low_search_home_bwd (lexmark_device);
1163141cc406Sopenharmony_ci    }
1164141cc406Sopenharmony_ci  /* do calibration before offset detection , use sensor max dpi, not motor's one */
1165141cc406Sopenharmony_ci  resolution = lexmark_device->val[OPT_RESOLUTION].w;
1166141cc406Sopenharmony_ci  if (resolution > 600)
1167141cc406Sopenharmony_ci    {
1168141cc406Sopenharmony_ci      resolution = 600;
1169141cc406Sopenharmony_ci    }
1170141cc406Sopenharmony_ci
1171141cc406Sopenharmony_ci
1172141cc406Sopenharmony_ci  sanei_lexmark_low_set_scan_regs (lexmark_device, resolution, 0, SANE_FALSE);
1173141cc406Sopenharmony_ci  status = sanei_lexmark_low_calibration (lexmark_device);
1174141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
1175141cc406Sopenharmony_ci    {
1176141cc406Sopenharmony_ci      DBG (1, "sane_start: calibration failed : %s ! \n",
1177141cc406Sopenharmony_ci	   sane_strstatus (status));
1178141cc406Sopenharmony_ci      return status;
1179141cc406Sopenharmony_ci    }
1180141cc406Sopenharmony_ci
1181141cc406Sopenharmony_ci  /* At this point we're somewhere in the dot. We need to read a number of
1182141cc406Sopenharmony_ci     lines greater than the diameter of the dot and determine how many lines
1183141cc406Sopenharmony_ci     past the dot we've gone. We then use this information to see how far the
1184141cc406Sopenharmony_ci     scan head must move before starting the scan. */
1185141cc406Sopenharmony_ci  /* offset is in 600 dpi unit */
1186141cc406Sopenharmony_ci  offset = sanei_lexmark_low_find_start_line (lexmark_device);
1187141cc406Sopenharmony_ci  DBG (7, "start line offset=%d\n", offset);
1188141cc406Sopenharmony_ci
1189141cc406Sopenharmony_ci  /* Set the shadow registers for scan with the options (resolution, mode,
1190141cc406Sopenharmony_ci     size) set in the front end. Pass the offset so we can get the vert.
1191141cc406Sopenharmony_ci     start. */
1192141cc406Sopenharmony_ci  sanei_lexmark_low_set_scan_regs (lexmark_device,
1193141cc406Sopenharmony_ci				   lexmark_device->val[OPT_RESOLUTION].w,
1194141cc406Sopenharmony_ci				   offset, SANE_TRUE);
1195141cc406Sopenharmony_ci
1196141cc406Sopenharmony_ci  if (sanei_lexmark_low_start_scan (lexmark_device) == SANE_STATUS_GOOD)
1197141cc406Sopenharmony_ci    {
1198141cc406Sopenharmony_ci      DBG (2, "sane_start: scan started\n");
1199141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1200141cc406Sopenharmony_ci    }
1201141cc406Sopenharmony_ci  else
1202141cc406Sopenharmony_ci    {
1203141cc406Sopenharmony_ci      lexmark_device->device_cancelled = SANE_TRUE;
1204141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1205141cc406Sopenharmony_ci    }
1206141cc406Sopenharmony_ci}
1207141cc406Sopenharmony_ci
1208141cc406Sopenharmony_ci
1209141cc406Sopenharmony_ciSANE_Status
1210141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * data,
1211141cc406Sopenharmony_ci	   SANE_Int max_length, SANE_Int * length)
1212141cc406Sopenharmony_ci{
1213141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device;
1214141cc406Sopenharmony_ci  long bytes_read;
1215141cc406Sopenharmony_ci
1216141cc406Sopenharmony_ci  DBG (2, "sane_read: handle=%p, data=%p, max_length = %d, length=%p\n",
1217141cc406Sopenharmony_ci       (void *) handle, (void *) data, max_length, (void *) length);
1218141cc406Sopenharmony_ci
1219141cc406Sopenharmony_ci  if (!initialized)
1220141cc406Sopenharmony_ci    {
1221141cc406Sopenharmony_ci      DBG (2, "sane_read: Not initialized\n");
1222141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1223141cc406Sopenharmony_ci    }
1224141cc406Sopenharmony_ci
1225141cc406Sopenharmony_ci  for (lexmark_device = first_lexmark_device; lexmark_device;
1226141cc406Sopenharmony_ci       lexmark_device = lexmark_device->next)
1227141cc406Sopenharmony_ci    {
1228141cc406Sopenharmony_ci      if (lexmark_device == handle)
1229141cc406Sopenharmony_ci	break;
1230141cc406Sopenharmony_ci    }
1231141cc406Sopenharmony_ci
1232141cc406Sopenharmony_ci  if (lexmark_device->device_cancelled)
1233141cc406Sopenharmony_ci    {
1234141cc406Sopenharmony_ci      DBG (2, "sane_read: Device was cancelled\n");
1235141cc406Sopenharmony_ci      /* We don't know how far we've gone, so search for home. */
1236141cc406Sopenharmony_ci      sanei_lexmark_low_search_home_bwd (lexmark_device);
1237141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
1238141cc406Sopenharmony_ci    }
1239141cc406Sopenharmony_ci
1240141cc406Sopenharmony_ci  if (!length)
1241141cc406Sopenharmony_ci    {
1242141cc406Sopenharmony_ci      DBG (2, "sane_read: NULL length pointer\n");
1243141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1244141cc406Sopenharmony_ci    }
1245141cc406Sopenharmony_ci
1246141cc406Sopenharmony_ci  *length = 0;
1247141cc406Sopenharmony_ci
1248141cc406Sopenharmony_ci  if (lexmark_device->eof)
1249141cc406Sopenharmony_ci    {
1250141cc406Sopenharmony_ci      DBG (2, "sane_read: Trying to read past EOF\n");
1251141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
1252141cc406Sopenharmony_ci    }
1253141cc406Sopenharmony_ci
1254141cc406Sopenharmony_ci  if (!data)
1255141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1256141cc406Sopenharmony_ci
1257141cc406Sopenharmony_ci  bytes_read = sanei_lexmark_low_read_scan_data (data, max_length,
1258141cc406Sopenharmony_ci						 lexmark_device);
1259141cc406Sopenharmony_ci  if (bytes_read < 0)
1260141cc406Sopenharmony_ci    return SANE_STATUS_IO_ERROR;
1261141cc406Sopenharmony_ci  else if (bytes_read == 0)
1262141cc406Sopenharmony_ci    return SANE_STATUS_EOF;
1263141cc406Sopenharmony_ci  else
1264141cc406Sopenharmony_ci    {
1265141cc406Sopenharmony_ci      *length = bytes_read;
1266141cc406Sopenharmony_ci      lexmark_device->data_ctr += bytes_read;
1267141cc406Sopenharmony_ci    }
1268141cc406Sopenharmony_ci
1269141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1270141cc406Sopenharmony_ci}
1271141cc406Sopenharmony_ci
1272141cc406Sopenharmony_civoid
1273141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
1274141cc406Sopenharmony_ci{
1275141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device;
1276141cc406Sopenharmony_ci/*   ssize_t bytes_read; */
1277141cc406Sopenharmony_ci  DBG (2, "sane_cancel: handle = %p\n", (void *) handle);
1278141cc406Sopenharmony_ci
1279141cc406Sopenharmony_ci  if (!initialized)
1280141cc406Sopenharmony_ci    return;
1281141cc406Sopenharmony_ci
1282141cc406Sopenharmony_ci
1283141cc406Sopenharmony_ci  for (lexmark_device = first_lexmark_device; lexmark_device;
1284141cc406Sopenharmony_ci       lexmark_device = lexmark_device->next)
1285141cc406Sopenharmony_ci    {
1286141cc406Sopenharmony_ci      if (lexmark_device == handle)
1287141cc406Sopenharmony_ci	break;
1288141cc406Sopenharmony_ci    }
1289141cc406Sopenharmony_ci
1290141cc406Sopenharmony_ci  /*If sane_cancel called more than once, return */
1291141cc406Sopenharmony_ci  if (++lexmark_device->cancel_ctr > 1)
1292141cc406Sopenharmony_ci    return;
1293141cc406Sopenharmony_ci
1294141cc406Sopenharmony_ci  /* Set the device flag so the next call to sane_read() can stop the scan. */
1295141cc406Sopenharmony_ci  lexmark_device->device_cancelled = SANE_TRUE;
1296141cc406Sopenharmony_ci
1297141cc406Sopenharmony_ci  return;
1298141cc406Sopenharmony_ci}
1299141cc406Sopenharmony_ci
1300141cc406Sopenharmony_ciSANE_Status
1301141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
1302141cc406Sopenharmony_ci{
1303141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device;
1304141cc406Sopenharmony_ci
1305141cc406Sopenharmony_ci  DBG (2, "sane_set_io_mode: handle = %p, non_blocking = %d\n",
1306141cc406Sopenharmony_ci       (void *) handle, non_blocking);
1307141cc406Sopenharmony_ci
1308141cc406Sopenharmony_ci  if (!initialized)
1309141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1310141cc406Sopenharmony_ci
1311141cc406Sopenharmony_ci  for (lexmark_device = first_lexmark_device; lexmark_device;
1312141cc406Sopenharmony_ci       lexmark_device = lexmark_device->next)
1313141cc406Sopenharmony_ci    {
1314141cc406Sopenharmony_ci      if (lexmark_device == handle)
1315141cc406Sopenharmony_ci	break;
1316141cc406Sopenharmony_ci    }
1317141cc406Sopenharmony_ci
1318141cc406Sopenharmony_ci  if (non_blocking)
1319141cc406Sopenharmony_ci    return SANE_STATUS_UNSUPPORTED;
1320141cc406Sopenharmony_ci
1321141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1322141cc406Sopenharmony_ci}
1323141cc406Sopenharmony_ci
1324141cc406Sopenharmony_ciSANE_Status
1325141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
1326141cc406Sopenharmony_ci{
1327141cc406Sopenharmony_ci  Lexmark_Device *lexmark_device;
1328141cc406Sopenharmony_ci
1329141cc406Sopenharmony_ci  DBG (2, "sane_get_select_fd: handle = %p, fd %s 0\n", (void *) handle,
1330141cc406Sopenharmony_ci       fd ? "!=" : "=");
1331141cc406Sopenharmony_ci
1332141cc406Sopenharmony_ci  if (!initialized)
1333141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1334141cc406Sopenharmony_ci
1335141cc406Sopenharmony_ci  for (lexmark_device = first_lexmark_device; lexmark_device;
1336141cc406Sopenharmony_ci       lexmark_device = lexmark_device->next)
1337141cc406Sopenharmony_ci    {
1338141cc406Sopenharmony_ci      if (lexmark_device == handle)
1339141cc406Sopenharmony_ci	break;
1340141cc406Sopenharmony_ci    }
1341141cc406Sopenharmony_ci
1342141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
1343141cc406Sopenharmony_ci}
1344141cc406Sopenharmony_ci
1345141cc406Sopenharmony_ci/***************************** END OF SANE API ****************************/
1346141cc406Sopenharmony_ci/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */
1347