1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2002, 2004 Frank Zago (sane at zago dot net)
4141cc406Sopenharmony_ci   Copyright (C) 2002 Other SANE contributors
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   This file is part of the SANE package.
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
9141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
10141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
11141cc406Sopenharmony_ci   License, or (at your option) any later version.
12141cc406Sopenharmony_ci
13141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
14141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
15141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16141cc406Sopenharmony_ci   General Public License for more details.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
19141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
22141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
25141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
26141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
27141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
28141cc406Sopenharmony_ci   account of linking the SANE library code into it.
29141cc406Sopenharmony_ci
30141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
31141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
32141cc406Sopenharmony_ci   License.
33141cc406Sopenharmony_ci
34141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
35141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
36141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
37141cc406Sopenharmony_ci
38141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
39141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
40141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
41141cc406Sopenharmony_ci*/
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci/*
44141cc406Sopenharmony_ci   Matsushita/Panasonic KV-SS25, KV-SS50, KV-SS55, KV-SS50EX,
45141cc406Sopenharmony_ci                        KV-SS55EX, KV-SS850, KV-SS855 SCSI scanners.
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci   This backend may support more Panasonic scanners.
48141cc406Sopenharmony_ci*/
49141cc406Sopenharmony_ci
50141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ci#define BUILD 7			/* 2004-02-11 */
53141cc406Sopenharmony_ci#define BACKEND_NAME matsushita
54141cc406Sopenharmony_ci#define MATSUSHITA_CONFIG_FILE "matsushita.conf"
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci#include "../include/sane/config.h"
59141cc406Sopenharmony_ci
60141cc406Sopenharmony_ci#include <errno.h>
61141cc406Sopenharmony_ci#include <fcntl.h>
62141cc406Sopenharmony_ci#include <limits.h>
63141cc406Sopenharmony_ci#include <signal.h>
64141cc406Sopenharmony_ci#include <stdio.h>
65141cc406Sopenharmony_ci#include <stdlib.h>
66141cc406Sopenharmony_ci#include <string.h>
67141cc406Sopenharmony_ci#include <sys/types.h>
68141cc406Sopenharmony_ci#include <sys/wait.h>
69141cc406Sopenharmony_ci#include <unistd.h>
70141cc406Sopenharmony_ci
71141cc406Sopenharmony_ci#include "../include/sane/sane.h"
72141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
73141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
74141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
75141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h"
76141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
77141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
78141cc406Sopenharmony_ci#include "../include/lassert.h"
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_ci#include "matsushita.h"
81141cc406Sopenharmony_ci
82141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_ci/* Lists of possible scan modes. */
85141cc406Sopenharmony_cistatic SANE_String_Const scan_mode_list_1[] = {
86141cc406Sopenharmony_ci  BLACK_WHITE_STR,
87141cc406Sopenharmony_ci  NULL
88141cc406Sopenharmony_ci};
89141cc406Sopenharmony_ci
90141cc406Sopenharmony_cistatic SANE_String_Const scan_mode_list_3[] = {
91141cc406Sopenharmony_ci  BLACK_WHITE_STR,
92141cc406Sopenharmony_ci  GRAY4_STR,
93141cc406Sopenharmony_ci  GRAY8_STR,
94141cc406Sopenharmony_ci  NULL
95141cc406Sopenharmony_ci};
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_ci/* Lists of supported resolutions (in DPI).
100141cc406Sopenharmony_ci *   200 DPI scanners are using resolutions_list_200
101141cc406Sopenharmony_ci *   300 DPI scanners are using resolutions_list_300
102141cc406Sopenharmony_ci *   400 DPI scanners are using resolutions_list_400
103141cc406Sopenharmony_ci *
104141cc406Sopenharmony_ci * The resolutions_rounds_* lists provide the value with which round
105141cc406Sopenharmony_ci * up the X value given by the interface.
106141cc406Sopenharmony_ci */
107141cc406Sopenharmony_ci#ifdef unused_yet
108141cc406Sopenharmony_cistatic const SANE_Word resolutions_list_200[4] = {
109141cc406Sopenharmony_ci  3, 100, 150, 200
110141cc406Sopenharmony_ci};
111141cc406Sopenharmony_cistatic const SANE_Word resolutions_rounds_200[4] = {
112141cc406Sopenharmony_ci  3, 0x100, 0x40, 0x20
113141cc406Sopenharmony_ci};
114141cc406Sopenharmony_ci#endif
115141cc406Sopenharmony_ci
116141cc406Sopenharmony_cistatic const SANE_Word resolutions_list_300[5] = {
117141cc406Sopenharmony_ci  4, 150, 200, 240, 300
118141cc406Sopenharmony_ci};
119141cc406Sopenharmony_cistatic const SANE_Word resolutions_rounds_300[5] = {
120141cc406Sopenharmony_ci  4, 0x100, 0x40, 0x20, 0x80
121141cc406Sopenharmony_ci};
122141cc406Sopenharmony_ci
123141cc406Sopenharmony_cistatic const SANE_Word resolutions_list_400[8] = {
124141cc406Sopenharmony_ci  7, 100, 150, 200, 240, 300, 360, 400
125141cc406Sopenharmony_ci};
126141cc406Sopenharmony_cistatic const SANE_Word resolutions_rounds_400[8] = {
127141cc406Sopenharmony_ci  7, 0x100, 0x100, 0x40, 0x20, 0x80, 0x100, 0x100	/* TO FIX */
128141cc406Sopenharmony_ci};
129141cc406Sopenharmony_ci
130141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
131141cc406Sopenharmony_ci
132141cc406Sopenharmony_ci/* Lists of supported halftone. They are only valid with
133141cc406Sopenharmony_ci * for the Black&White mode. */
134141cc406Sopenharmony_cistatic SANE_String_Const halftone_pattern_list[] = {
135141cc406Sopenharmony_ci  SANE_I18N ("None"),
136141cc406Sopenharmony_ci  SANE_I18N ("Bayer Dither 16"),
137141cc406Sopenharmony_ci  SANE_I18N ("Bayer Dither 64"),
138141cc406Sopenharmony_ci  SANE_I18N ("Halftone Dot 32"),
139141cc406Sopenharmony_ci  SANE_I18N ("Halftone Dot 64"),
140141cc406Sopenharmony_ci  SANE_I18N ("Error Diffusion"),
141141cc406Sopenharmony_ci  NULL
142141cc406Sopenharmony_ci};
143141cc406Sopenharmony_cistatic const int halftone_pattern_val[] = {
144141cc406Sopenharmony_ci  -1,
145141cc406Sopenharmony_ci  0x01,
146141cc406Sopenharmony_ci  0x00,
147141cc406Sopenharmony_ci  0x02,
148141cc406Sopenharmony_ci  0x03,
149141cc406Sopenharmony_ci  0x04
150141cc406Sopenharmony_ci};
151141cc406Sopenharmony_ci
152141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
153141cc406Sopenharmony_ci
154141cc406Sopenharmony_ci/* List of automatic threshold options */
155141cc406Sopenharmony_cistatic SANE_String_Const automatic_threshold_list[] = {
156141cc406Sopenharmony_ci  SANE_I18N ("None"),
157141cc406Sopenharmony_ci  SANE_I18N ("Mode 1"),
158141cc406Sopenharmony_ci  SANE_I18N ("Mode 2"),
159141cc406Sopenharmony_ci  SANE_I18N ("Mode 3"),
160141cc406Sopenharmony_ci  NULL
161141cc406Sopenharmony_ci};
162141cc406Sopenharmony_cistatic const int automatic_threshold_val[] = {
163141cc406Sopenharmony_ci  0,
164141cc406Sopenharmony_ci  0x80,
165141cc406Sopenharmony_ci  0x81,
166141cc406Sopenharmony_ci  0x82
167141cc406Sopenharmony_ci};
168141cc406Sopenharmony_ci
169141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
170141cc406Sopenharmony_ci
171141cc406Sopenharmony_ci/* List of white level base. */
172141cc406Sopenharmony_cistatic SANE_String_Const white_level_list[] = {
173141cc406Sopenharmony_ci  SANE_I18N ("From white stick"),
174141cc406Sopenharmony_ci  SANE_I18N ("From paper"),
175141cc406Sopenharmony_ci  SANE_I18N ("Automatic"),
176141cc406Sopenharmony_ci  NULL
177141cc406Sopenharmony_ci};
178141cc406Sopenharmony_cistatic const int white_level_val[] = {
179141cc406Sopenharmony_ci  0x00,
180141cc406Sopenharmony_ci  0x80,
181141cc406Sopenharmony_ci  0x81
182141cc406Sopenharmony_ci};
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
185141cc406Sopenharmony_ci
186141cc406Sopenharmony_ci/* List of noise reduction options. */
187141cc406Sopenharmony_cistatic SANE_String_Const noise_reduction_list[] = {
188141cc406Sopenharmony_ci  SANE_I18N ("None"),
189141cc406Sopenharmony_ci  "1x1",
190141cc406Sopenharmony_ci  "2x2",
191141cc406Sopenharmony_ci  "3x3",
192141cc406Sopenharmony_ci  "4x4",
193141cc406Sopenharmony_ci  "5x5",
194141cc406Sopenharmony_ci  NULL
195141cc406Sopenharmony_ci};
196141cc406Sopenharmony_cistatic const int noise_reduction_val[] = {
197141cc406Sopenharmony_ci  0x00,
198141cc406Sopenharmony_ci  0x01,
199141cc406Sopenharmony_ci  0x02,
200141cc406Sopenharmony_ci  0x03,
201141cc406Sopenharmony_ci  0x04,
202141cc406Sopenharmony_ci  0x05
203141cc406Sopenharmony_ci};
204141cc406Sopenharmony_ci
205141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
206141cc406Sopenharmony_ci
207141cc406Sopenharmony_ci/* List of image emphasis options, 5 steps */
208141cc406Sopenharmony_cistatic SANE_String_Const image_emphasis_list_5[] = {
209141cc406Sopenharmony_ci  SANE_I18N ("Smooth"),
210141cc406Sopenharmony_ci  SANE_I18N ("None"),
211141cc406Sopenharmony_ci  SANE_I18N ("Low"),
212141cc406Sopenharmony_ci  SANE_I18N ("Medium"),		/* default */
213141cc406Sopenharmony_ci  SANE_I18N ("High"),
214141cc406Sopenharmony_ci  NULL
215141cc406Sopenharmony_ci};
216141cc406Sopenharmony_cistatic const int image_emphasis_val_5[] = {
217141cc406Sopenharmony_ci  0x80,
218141cc406Sopenharmony_ci  0x00,
219141cc406Sopenharmony_ci  0x01,
220141cc406Sopenharmony_ci  0x30,
221141cc406Sopenharmony_ci  0x50
222141cc406Sopenharmony_ci};
223141cc406Sopenharmony_ci
224141cc406Sopenharmony_ci/* List of image emphasis options, 3 steps */
225141cc406Sopenharmony_cistatic SANE_String_Const image_emphasis_list_3[] = {
226141cc406Sopenharmony_ci  SANE_I18N ("Low"),
227141cc406Sopenharmony_ci  SANE_I18N ("Medium"),		/* default ? */
228141cc406Sopenharmony_ci  SANE_I18N ("High"),
229141cc406Sopenharmony_ci  NULL
230141cc406Sopenharmony_ci};
231141cc406Sopenharmony_cistatic const int image_emphasis_val_3[] = {
232141cc406Sopenharmony_ci  0x01,
233141cc406Sopenharmony_ci  0x30,
234141cc406Sopenharmony_ci  0x50
235141cc406Sopenharmony_ci};
236141cc406Sopenharmony_ci
237141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
238141cc406Sopenharmony_ci
239141cc406Sopenharmony_ci/* List of gamma */
240141cc406Sopenharmony_cistatic SANE_String_Const gamma_list[] = {
241141cc406Sopenharmony_ci  SANE_I18N ("Normal"),
242141cc406Sopenharmony_ci  SANE_I18N ("CRT"),
243141cc406Sopenharmony_ci  NULL
244141cc406Sopenharmony_ci};
245141cc406Sopenharmony_cistatic const int gamma_val[] = {
246141cc406Sopenharmony_ci  0x00,
247141cc406Sopenharmony_ci  0x01
248141cc406Sopenharmony_ci};
249141cc406Sopenharmony_ci
250141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
251141cc406Sopenharmony_ci
252141cc406Sopenharmony_ci/* Page feeder options */
253141cc406Sopenharmony_cistatic SANE_String_Const feeder_mode_list[] = {
254141cc406Sopenharmony_ci  SANE_I18N ("One page"),
255141cc406Sopenharmony_ci  SANE_I18N ("All pages"),
256141cc406Sopenharmony_ci  NULL
257141cc406Sopenharmony_ci};
258141cc406Sopenharmony_cistatic const int feeder_mode_val[] = {
259141cc406Sopenharmony_ci  0x00,
260141cc406Sopenharmony_ci  0xff
261141cc406Sopenharmony_ci};
262141cc406Sopenharmony_ci
263141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
264141cc406Sopenharmony_ci
265141cc406Sopenharmony_ci/* Paper size in millimeters.
266141cc406Sopenharmony_ci * Values from http://www.twics.com/~eds/paper/. */
267141cc406Sopenharmony_cistatic const struct paper_sizes paper_sizes[] = {
268141cc406Sopenharmony_ci  {"2A0", 1189, 1682},
269141cc406Sopenharmony_ci  {"4A0", 1682, 2378},
270141cc406Sopenharmony_ci  {"A0", 841, 1189},
271141cc406Sopenharmony_ci  {"A1", 594, 841},
272141cc406Sopenharmony_ci  {"A2", 420, 594},
273141cc406Sopenharmony_ci  {"A3", 297, 420},
274141cc406Sopenharmony_ci  {"A4", 210, 297},
275141cc406Sopenharmony_ci  {"A5", 148, 210},
276141cc406Sopenharmony_ci  {"A6", 105, 148},
277141cc406Sopenharmony_ci  {"A7", 74, 105},
278141cc406Sopenharmony_ci  {"A8", 52, 74},
279141cc406Sopenharmony_ci  {"A9", 37, 52},
280141cc406Sopenharmony_ci  {"A10", 26, 37},
281141cc406Sopenharmony_ci  {"B0", 1000, 1414},
282141cc406Sopenharmony_ci  {"B1", 707, 1000},
283141cc406Sopenharmony_ci  {"B2", 500, 707},
284141cc406Sopenharmony_ci  {"B3", 353, 500},
285141cc406Sopenharmony_ci  {"B4", 250, 353},
286141cc406Sopenharmony_ci  {"B5", 176, 250},
287141cc406Sopenharmony_ci  {"B6", 125, 176},
288141cc406Sopenharmony_ci  {"B7", 88, 125},
289141cc406Sopenharmony_ci  {"B8", 62, 88},
290141cc406Sopenharmony_ci  {"B9", 44, 62},
291141cc406Sopenharmony_ci  {"B10", 31, 44},
292141cc406Sopenharmony_ci  {"C0", 917, 1297},
293141cc406Sopenharmony_ci  {"C1", 648, 917},
294141cc406Sopenharmony_ci  {"C2", 458, 648},
295141cc406Sopenharmony_ci  {"C3", 324, 458},
296141cc406Sopenharmony_ci  {"C4", 229, 324},
297141cc406Sopenharmony_ci  {"C5", 162, 229},
298141cc406Sopenharmony_ci  {"C6", 114, 162},
299141cc406Sopenharmony_ci  {"C7", 81, 114},
300141cc406Sopenharmony_ci  {"C8", 57, 81},
301141cc406Sopenharmony_ci  {"C9", 40, 57},
302141cc406Sopenharmony_ci  {"C10", 28, 40},
303141cc406Sopenharmony_ci  {"Legal", 8.5 * MM_PER_INCH, 14 * MM_PER_INCH},
304141cc406Sopenharmony_ci  {"Letter", 8.5 * MM_PER_INCH, 11 * MM_PER_INCH}
305141cc406Sopenharmony_ci};
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
308141cc406Sopenharmony_ci
309141cc406Sopenharmony_ci/* Define the supported scanners and their characteristics. */
310141cc406Sopenharmony_cistatic const struct scanners_supported scanners[] = {
311141cc406Sopenharmony_ci
312141cc406Sopenharmony_ci  /* Panasonic KV-SS25 */
313141cc406Sopenharmony_ci  {
314141cc406Sopenharmony_ci   0x06, "K.M.E.  ", "KV-SS25A        ",
315141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (8.5 * MM_PER_INCH), 0},	/* x range 0 to 215.9 mm */
316141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (17 * MM_PER_INCH), 0},	/* y range 0 to 431.8 mm */
317141cc406Sopenharmony_ci   {1, 255, 1},			/* brightness range */
318141cc406Sopenharmony_ci   {1, 255, 1},			/* contrast range */
319141cc406Sopenharmony_ci   scan_mode_list_3,
320141cc406Sopenharmony_ci   resolutions_list_300, resolutions_rounds_300,
321141cc406Sopenharmony_ci   image_emphasis_list_5, image_emphasis_val_5,
322141cc406Sopenharmony_ci   MAT_CAP_DUPLEX | MAT_CAP_CONTRAST |
323141cc406Sopenharmony_ci   MAT_CAP_AUTOMATIC_THRESHOLD | MAT_CAP_WHITE_LEVEL | MAT_CAP_GAMMA |
324141cc406Sopenharmony_ci   MAT_CAP_NOISE_REDUCTION},
325141cc406Sopenharmony_ci
326141cc406Sopenharmony_ci  /* Panasonic KV-SS25D */
327141cc406Sopenharmony_ci  {
328141cc406Sopenharmony_ci   0x06, "K.M.E.  ", "KV-SS25D        ",	/* TO FIX */
329141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (8.5 * MM_PER_INCH), 0},	/* x range 0 to 215.9 mm */
330141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (17 * MM_PER_INCH), 0},	/* y range 0 to 431.8 mm */
331141cc406Sopenharmony_ci   {1, 255, 1},			/* brightness range */
332141cc406Sopenharmony_ci   {1, 255, 1},			/* contrast range */
333141cc406Sopenharmony_ci   scan_mode_list_3,
334141cc406Sopenharmony_ci   resolutions_list_300, resolutions_rounds_300,
335141cc406Sopenharmony_ci   image_emphasis_list_5, image_emphasis_val_5,
336141cc406Sopenharmony_ci   MAT_CAP_DUPLEX | MAT_CAP_CONTRAST |
337141cc406Sopenharmony_ci   MAT_CAP_AUTOMATIC_THRESHOLD | MAT_CAP_WHITE_LEVEL | MAT_CAP_GAMMA |
338141cc406Sopenharmony_ci   MAT_CAP_NOISE_REDUCTION},
339141cc406Sopenharmony_ci
340141cc406Sopenharmony_ci  /* Panasonic KV-SS50 */
341141cc406Sopenharmony_ci  {
342141cc406Sopenharmony_ci   0x06, "K.M.E.  ", "KV-SS50         ",	/* TO FIX */
343141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (8.5 * MM_PER_INCH), 0},	/* x range 0 to 215.9 mm */
344141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (14 * MM_PER_INCH), 0},	/* y range 0 to 355.6 mm */
345141cc406Sopenharmony_ci   {1, 5, 1},			/* brightness range, TO FIX */
346141cc406Sopenharmony_ci   {0, 0, 0},			/* contrast range */
347141cc406Sopenharmony_ci   scan_mode_list_1,
348141cc406Sopenharmony_ci   resolutions_list_300, resolutions_rounds_300,	/* TO FIX */
349141cc406Sopenharmony_ci   image_emphasis_list_3, image_emphasis_val_3,
350141cc406Sopenharmony_ci   MAT_CAP_PAPER_DETECT | MAT_CAP_MIRROR_IMAGE},
351141cc406Sopenharmony_ci
352141cc406Sopenharmony_ci  /* Panasonic KV-SS55 */
353141cc406Sopenharmony_ci  {
354141cc406Sopenharmony_ci   0x06, "K.M.E.  ", "KV-SS55         ",	/* TO FIX */
355141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (8.5 * MM_PER_INCH), 0},	/* x range 0 to 215.9 mm */
356141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (14 * MM_PER_INCH), 0},	/* y range 0 to 355.6 mm */
357141cc406Sopenharmony_ci   {1, 5, 1},			/* brightness range, TO FIX */
358141cc406Sopenharmony_ci   {1, 255, 1},			/* contrast range, TO FIX */
359141cc406Sopenharmony_ci   scan_mode_list_1,
360141cc406Sopenharmony_ci   resolutions_list_300, resolutions_rounds_300,	/* TO FIX */
361141cc406Sopenharmony_ci   image_emphasis_list_3, image_emphasis_val_3,
362141cc406Sopenharmony_ci   MAT_CAP_DUPLEX | MAT_CAP_CONTRAST | MAT_CAP_PAPER_DETECT |
363141cc406Sopenharmony_ci   MAT_CAP_MIRROR_IMAGE},
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci  /* Panasonic KV-SS50EX */
366141cc406Sopenharmony_ci  {
367141cc406Sopenharmony_ci   0x06, "K.M.E.  ", "KV-SS50EX       ",	/* TO FIX */
368141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (8.5 * MM_PER_INCH), 0},	/* x range 0 to 215.9 mm */
369141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (17 * MM_PER_INCH), 0},	/* y range 0 to 355.6 mm */
370141cc406Sopenharmony_ci   {1, 255, 1},			/* brightness range */
371141cc406Sopenharmony_ci   {0, 0, 0},			/* contrast range */
372141cc406Sopenharmony_ci   scan_mode_list_3,
373141cc406Sopenharmony_ci   resolutions_list_300, resolutions_rounds_300,	/* TO FIX */
374141cc406Sopenharmony_ci   image_emphasis_list_5, image_emphasis_val_5,
375141cc406Sopenharmony_ci   MAT_CAP_AUTOMATIC_THRESHOLD | MAT_CAP_WHITE_LEVEL | MAT_CAP_GAMMA |
376141cc406Sopenharmony_ci   MAT_CAP_NOISE_REDUCTION | MAT_CAP_PAPER_DETECT | MAT_CAP_MIRROR_IMAGE},
377141cc406Sopenharmony_ci
378141cc406Sopenharmony_ci  /* Panasonic KV-SS55EX */
379141cc406Sopenharmony_ci  {
380141cc406Sopenharmony_ci   0x06, "K.M.E.  ", "KV-SS55EX       ",
381141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (8.5 * MM_PER_INCH), 0},	/* x range 0 to 215.9 mm */
382141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (17 * MM_PER_INCH), 0},	/* y range 0 to 431.8 mm */
383141cc406Sopenharmony_ci   {1, 255, 1},			/* brightness range */
384141cc406Sopenharmony_ci   {1, 255, 1},			/* contrast range */
385141cc406Sopenharmony_ci   scan_mode_list_3,
386141cc406Sopenharmony_ci   resolutions_list_300, resolutions_rounds_300,
387141cc406Sopenharmony_ci   image_emphasis_list_5, image_emphasis_val_5,
388141cc406Sopenharmony_ci   MAT_CAP_DUPLEX | MAT_CAP_CONTRAST |
389141cc406Sopenharmony_ci   MAT_CAP_AUTOMATIC_THRESHOLD | MAT_CAP_WHITE_LEVEL | MAT_CAP_GAMMA |
390141cc406Sopenharmony_ci   MAT_CAP_NOISE_REDUCTION},
391141cc406Sopenharmony_ci
392141cc406Sopenharmony_ci  /* Panasonic KV-SS850 */
393141cc406Sopenharmony_ci  {
394141cc406Sopenharmony_ci   0x06, "K.M.E.  ", "KV-SS850        ",	/* TO FIX */
395141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (11.5 * MM_PER_INCH), 0},	/* x range 0 to 215.9 mm */
396141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (17 * MM_PER_INCH), 0},	/* y range 0 to 355.6 mm */
397141cc406Sopenharmony_ci   {1, 255, 1},			/* brightness range */
398141cc406Sopenharmony_ci   {0, 0, 0},			/* contrast range */
399141cc406Sopenharmony_ci   scan_mode_list_3,
400141cc406Sopenharmony_ci   resolutions_list_300, resolutions_rounds_300,	/* TO FIX */
401141cc406Sopenharmony_ci   image_emphasis_list_5, image_emphasis_val_5,
402141cc406Sopenharmony_ci   MAT_CAP_AUTOMATIC_THRESHOLD | MAT_CAP_WHITE_LEVEL |
403141cc406Sopenharmony_ci   MAT_CAP_GAMMA | MAT_CAP_NOISE_REDUCTION | MAT_CAP_PAPER_DETECT |
404141cc406Sopenharmony_ci   MAT_CAP_DETECT_DOUBLE_FEED | MAT_CAP_MANUAL_FEED},
405141cc406Sopenharmony_ci
406141cc406Sopenharmony_ci  /* Panasonic KV-SS855 */
407141cc406Sopenharmony_ci  {
408141cc406Sopenharmony_ci   0x06, "K.M.E.  ", "KV-SS855        ",	/* TO FIX */
409141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (11.5 * MM_PER_INCH), 0},	/* x range 0 to 215.9 mm */
410141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (17 * MM_PER_INCH), 0},	/* y range 0 to 355.6 mm */
411141cc406Sopenharmony_ci   {1, 255, 1},			/* brightness range */
412141cc406Sopenharmony_ci   {1, 255, 1},			/* contrast range, TO FIX */
413141cc406Sopenharmony_ci   scan_mode_list_3,
414141cc406Sopenharmony_ci   resolutions_list_400, resolutions_rounds_400,	/* TO FIX */
415141cc406Sopenharmony_ci   image_emphasis_list_5, image_emphasis_val_5,
416141cc406Sopenharmony_ci   MAT_CAP_DUPLEX | MAT_CAP_CONTRAST | MAT_CAP_AUTOMATIC_THRESHOLD |
417141cc406Sopenharmony_ci   MAT_CAP_WHITE_LEVEL | MAT_CAP_GAMMA | MAT_CAP_NOISE_REDUCTION |
418141cc406Sopenharmony_ci   MAT_CAP_PAPER_DETECT | MAT_CAP_DETECT_DOUBLE_FEED | MAT_CAP_MANUAL_FEED},
419141cc406Sopenharmony_ci
420141cc406Sopenharmony_ci  /* Panasonic KV-S2065L */
421141cc406Sopenharmony_ci  {
422141cc406Sopenharmony_ci   0x06, "K.M.E.  ", "KV-S2065L       ",
423141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (8.5 * MM_PER_INCH), 0},	/* x range 0 to 215.9 mm */
424141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (17 * MM_PER_INCH), 0},	/* y range 0 to 431.8 mm */
425141cc406Sopenharmony_ci   {1, 255, 1},			/* brightness range */
426141cc406Sopenharmony_ci   {1, 255, 1},			/* contrast range */
427141cc406Sopenharmony_ci   scan_mode_list_3,
428141cc406Sopenharmony_ci   resolutions_list_300, resolutions_rounds_300,
429141cc406Sopenharmony_ci   image_emphasis_list_5, image_emphasis_val_5,
430141cc406Sopenharmony_ci   MAT_CAP_DUPLEX | MAT_CAP_CONTRAST |
431141cc406Sopenharmony_ci   MAT_CAP_AUTOMATIC_THRESHOLD | MAT_CAP_WHITE_LEVEL | MAT_CAP_GAMMA |
432141cc406Sopenharmony_ci   MAT_CAP_NOISE_REDUCTION},
433141cc406Sopenharmony_ci
434141cc406Sopenharmony_ci  /* Panasonic KV-S2025C */
435141cc406Sopenharmony_ci  {
436141cc406Sopenharmony_ci   0x06, "K.M.E.  ", "KV-S2025C       ",
437141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (8.5 * MM_PER_INCH), 0},	/* x range 0 to 215.9 mm */
438141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (17 * MM_PER_INCH), 0},	/* y range 0 to 431.8 mm */
439141cc406Sopenharmony_ci   {1, 255, 1},			/* brightness range */
440141cc406Sopenharmony_ci   {1, 255, 1},			/* contrast range */
441141cc406Sopenharmony_ci   scan_mode_list_3,
442141cc406Sopenharmony_ci   resolutions_list_300, resolutions_rounds_300,
443141cc406Sopenharmony_ci   image_emphasis_list_5, image_emphasis_val_5,
444141cc406Sopenharmony_ci   MAT_CAP_DUPLEX | MAT_CAP_CONTRAST |
445141cc406Sopenharmony_ci   MAT_CAP_AUTOMATIC_THRESHOLD | MAT_CAP_WHITE_LEVEL | MAT_CAP_GAMMA |
446141cc406Sopenharmony_ci   MAT_CAP_NOISE_REDUCTION},
447141cc406Sopenharmony_ci
448141cc406Sopenharmony_ci  /* Panasonic KV-S2045C */
449141cc406Sopenharmony_ci  {
450141cc406Sopenharmony_ci   0x06, "K.M.E.  ", "KV-S2045C       ",
451141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (8.5 * MM_PER_INCH), 0},	/* x range 0 to 215.9 mm */
452141cc406Sopenharmony_ci   {SANE_FIX (0), SANE_FIX (17 * MM_PER_INCH), 0},	/* y range 0 to 431.8 mm */
453141cc406Sopenharmony_ci   {1, 255, 1},			/* brightness range */
454141cc406Sopenharmony_ci   {1, 255, 1},			/* contrast range */
455141cc406Sopenharmony_ci   scan_mode_list_3,
456141cc406Sopenharmony_ci   resolutions_list_300, resolutions_rounds_300,
457141cc406Sopenharmony_ci   image_emphasis_list_5, image_emphasis_val_5,
458141cc406Sopenharmony_ci   MAT_CAP_DUPLEX | MAT_CAP_CONTRAST |
459141cc406Sopenharmony_ci   MAT_CAP_AUTOMATIC_THRESHOLD | MAT_CAP_WHITE_LEVEL | MAT_CAP_GAMMA |
460141cc406Sopenharmony_ci   MAT_CAP_NOISE_REDUCTION}
461141cc406Sopenharmony_ci};
462141cc406Sopenharmony_ci
463141cc406Sopenharmony_ci
464141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
465141cc406Sopenharmony_ci
466141cc406Sopenharmony_ci/* List of scanner attached. */
467141cc406Sopenharmony_cistatic Matsushita_Scanner *first_dev = NULL;
468141cc406Sopenharmony_cistatic int num_devices = 0;
469141cc406Sopenharmony_cistatic const SANE_Device **devlist = NULL;
470141cc406Sopenharmony_ci
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci/* Local functions. */
473141cc406Sopenharmony_ci
474141cc406Sopenharmony_ci/* Display a buffer in the log. */
475141cc406Sopenharmony_cistatic void
476141cc406Sopenharmony_cihexdump (int level, const char *comment, unsigned char *p, int l)
477141cc406Sopenharmony_ci{
478141cc406Sopenharmony_ci  int i;
479141cc406Sopenharmony_ci  char line[128];
480141cc406Sopenharmony_ci  char *ptr;
481141cc406Sopenharmony_ci
482141cc406Sopenharmony_ci  DBG (level, "%s\n", comment);
483141cc406Sopenharmony_ci  ptr = line;
484141cc406Sopenharmony_ci  for (i = 0; i < l; i++, p++)
485141cc406Sopenharmony_ci    {
486141cc406Sopenharmony_ci      if ((i % 16) == 0)
487141cc406Sopenharmony_ci	{
488141cc406Sopenharmony_ci	  if (ptr != line)
489141cc406Sopenharmony_ci	    {
490141cc406Sopenharmony_ci	      *ptr = '\0';
491141cc406Sopenharmony_ci	      DBG (level, "%s\n", line);
492141cc406Sopenharmony_ci	      ptr = line;
493141cc406Sopenharmony_ci	    }
494141cc406Sopenharmony_ci	  sprintf (ptr, "%3.3d:", i);
495141cc406Sopenharmony_ci	  ptr += 4;
496141cc406Sopenharmony_ci	}
497141cc406Sopenharmony_ci      sprintf (ptr, " %2.2x", *p);
498141cc406Sopenharmony_ci      ptr += 3;
499141cc406Sopenharmony_ci    }
500141cc406Sopenharmony_ci  *ptr = '\0';
501141cc406Sopenharmony_ci  DBG (level, "%s\n", line);
502141cc406Sopenharmony_ci}
503141cc406Sopenharmony_ci
504141cc406Sopenharmony_ci/* Returns the length of the longest string, including the terminating
505141cc406Sopenharmony_ci * character. */
506141cc406Sopenharmony_cistatic size_t
507141cc406Sopenharmony_cimax_string_size (SANE_String_Const strings[])
508141cc406Sopenharmony_ci{
509141cc406Sopenharmony_ci  size_t size, max_size = 0;
510141cc406Sopenharmony_ci  int i;
511141cc406Sopenharmony_ci
512141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
513141cc406Sopenharmony_ci    {
514141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
515141cc406Sopenharmony_ci      if (size > max_size)
516141cc406Sopenharmony_ci	{
517141cc406Sopenharmony_ci	  max_size = size;
518141cc406Sopenharmony_ci	}
519141cc406Sopenharmony_ci    }
520141cc406Sopenharmony_ci
521141cc406Sopenharmony_ci  return max_size;
522141cc406Sopenharmony_ci}
523141cc406Sopenharmony_ci
524141cc406Sopenharmony_ci/* After the windows has been set, issue that command to get the
525141cc406Sopenharmony_ci * document size. */
526141cc406Sopenharmony_cistatic SANE_Status
527141cc406Sopenharmony_cimatsushita_read_document_size (Matsushita_Scanner * dev)
528141cc406Sopenharmony_ci{
529141cc406Sopenharmony_ci  CDB cdb;
530141cc406Sopenharmony_ci  SANE_Status status;
531141cc406Sopenharmony_ci  size_t size;
532141cc406Sopenharmony_ci
533141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_read_document_size: enter\n");
534141cc406Sopenharmony_ci
535141cc406Sopenharmony_ci  size = 0x10;
536141cc406Sopenharmony_ci  MKSCSI_READ_10 (cdb, 0x80, 0, size);
537141cc406Sopenharmony_ci
538141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
539141cc406Sopenharmony_ci			    NULL, 0, dev->buffer, &size);
540141cc406Sopenharmony_ci
541141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD || size != 0x10)
542141cc406Sopenharmony_ci    {
543141cc406Sopenharmony_ci      DBG (DBG_error,
544141cc406Sopenharmony_ci	   "matsushita_read_document_size: cannot read document size\n");
545141cc406Sopenharmony_ci      return (SANE_STATUS_IO_ERROR);
546141cc406Sopenharmony_ci    }
547141cc406Sopenharmony_ci
548141cc406Sopenharmony_ci  hexdump (DBG_info2, "document size", dev->buffer, 16);
549141cc406Sopenharmony_ci
550141cc406Sopenharmony_ci  /* Check that X and Y are the same values the backend computed. */
551141cc406Sopenharmony_ci
552141cc406Sopenharmony_ci  assert (dev->params.lines == B32TOI (&dev->buffer[4]));
553141cc406Sopenharmony_ci  assert (dev->params.pixels_per_line == B32TOI (&dev->buffer[0]));
554141cc406Sopenharmony_ci
555141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_read_document_size: exit, %ld bytes read\n",
556141cc406Sopenharmony_ci       (long)size);
557141cc406Sopenharmony_ci
558141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);
559141cc406Sopenharmony_ci}
560141cc406Sopenharmony_ci
561141cc406Sopenharmony_ci/* Initialize a scanner entry. Return an allocated scanner with some
562141cc406Sopenharmony_ci * preset values. */
563141cc406Sopenharmony_cistatic Matsushita_Scanner *
564141cc406Sopenharmony_cimatsushita_init (void)
565141cc406Sopenharmony_ci{
566141cc406Sopenharmony_ci  Matsushita_Scanner *dev;
567141cc406Sopenharmony_ci
568141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_init: enter\n");
569141cc406Sopenharmony_ci
570141cc406Sopenharmony_ci  /* Allocate a new scanner entry. */
571141cc406Sopenharmony_ci  dev = malloc (sizeof (Matsushita_Scanner));
572141cc406Sopenharmony_ci  if (dev == NULL)
573141cc406Sopenharmony_ci    {
574141cc406Sopenharmony_ci      return NULL;
575141cc406Sopenharmony_ci    }
576141cc406Sopenharmony_ci
577141cc406Sopenharmony_ci  memset (dev, 0, sizeof (Matsushita_Scanner));
578141cc406Sopenharmony_ci
579141cc406Sopenharmony_ci  /* Allocate the buffer used to transfer the SCSI data. */
580141cc406Sopenharmony_ci  dev->buffer_size = 64 * 1024;
581141cc406Sopenharmony_ci  dev->buffer = malloc (dev->buffer_size);
582141cc406Sopenharmony_ci  if (dev->buffer == NULL)
583141cc406Sopenharmony_ci    {
584141cc406Sopenharmony_ci      free (dev);
585141cc406Sopenharmony_ci      return NULL;
586141cc406Sopenharmony_ci    }
587141cc406Sopenharmony_ci
588141cc406Sopenharmony_ci  /* Allocate a buffer to store the temporary image. */
589141cc406Sopenharmony_ci  dev->image_size = 64 * 1024;	/* enough for 1 line at max res */
590141cc406Sopenharmony_ci  dev->image = malloc (dev->image_size);
591141cc406Sopenharmony_ci  if (dev->image == NULL)
592141cc406Sopenharmony_ci    {
593141cc406Sopenharmony_ci      free (dev->buffer);
594141cc406Sopenharmony_ci      free (dev);
595141cc406Sopenharmony_ci      return NULL;
596141cc406Sopenharmony_ci    }
597141cc406Sopenharmony_ci
598141cc406Sopenharmony_ci  dev->sfd = -1;
599141cc406Sopenharmony_ci
600141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_init: exit\n");
601141cc406Sopenharmony_ci
602141cc406Sopenharmony_ci  return (dev);
603141cc406Sopenharmony_ci}
604141cc406Sopenharmony_ci
605141cc406Sopenharmony_ci/* Closes an open scanner. */
606141cc406Sopenharmony_cistatic void
607141cc406Sopenharmony_cimatsushita_close (Matsushita_Scanner * dev)
608141cc406Sopenharmony_ci{
609141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_close: enter\n");
610141cc406Sopenharmony_ci
611141cc406Sopenharmony_ci  if (dev->sfd != -1)
612141cc406Sopenharmony_ci    {
613141cc406Sopenharmony_ci      sanei_scsi_close (dev->sfd);
614141cc406Sopenharmony_ci      dev->sfd = -1;
615141cc406Sopenharmony_ci    }
616141cc406Sopenharmony_ci
617141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_close: exit\n");
618141cc406Sopenharmony_ci}
619141cc406Sopenharmony_ci
620141cc406Sopenharmony_ci/* Frees the memory used by a scanner. */
621141cc406Sopenharmony_cistatic void
622141cc406Sopenharmony_cimatsushita_free (Matsushita_Scanner * dev)
623141cc406Sopenharmony_ci{
624141cc406Sopenharmony_ci  int i;
625141cc406Sopenharmony_ci
626141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_free: enter\n");
627141cc406Sopenharmony_ci
628141cc406Sopenharmony_ci  if (dev == NULL)
629141cc406Sopenharmony_ci    return;
630141cc406Sopenharmony_ci
631141cc406Sopenharmony_ci  matsushita_close (dev);
632141cc406Sopenharmony_ci  if (dev->devicename)
633141cc406Sopenharmony_ci    {
634141cc406Sopenharmony_ci      free (dev->devicename);
635141cc406Sopenharmony_ci    }
636141cc406Sopenharmony_ci  if (dev->buffer)
637141cc406Sopenharmony_ci    {
638141cc406Sopenharmony_ci      free (dev->buffer);
639141cc406Sopenharmony_ci    }
640141cc406Sopenharmony_ci  if (dev->image)
641141cc406Sopenharmony_ci    {
642141cc406Sopenharmony_ci      free (dev->image);
643141cc406Sopenharmony_ci    }
644141cc406Sopenharmony_ci  for (i = 1; i < OPT_NUM_OPTIONS; i++)
645141cc406Sopenharmony_ci    {
646141cc406Sopenharmony_ci      if (dev->opt[i].type == SANE_TYPE_STRING && dev->val[i].s)
647141cc406Sopenharmony_ci	{
648141cc406Sopenharmony_ci	  free (dev->val[i].s);
649141cc406Sopenharmony_ci	}
650141cc406Sopenharmony_ci    }
651141cc406Sopenharmony_ci  free (dev->paper_sizes_list);
652141cc406Sopenharmony_ci  free (dev->paper_sizes_val);
653141cc406Sopenharmony_ci
654141cc406Sopenharmony_ci  free (dev);
655141cc406Sopenharmony_ci
656141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_free: exit\n");
657141cc406Sopenharmony_ci}
658141cc406Sopenharmony_ci
659141cc406Sopenharmony_ci/* Inquiry a device and returns TRUE if is supported. */
660141cc406Sopenharmony_cistatic int
661141cc406Sopenharmony_cimatsushita_identify_scanner (Matsushita_Scanner * dev)
662141cc406Sopenharmony_ci{
663141cc406Sopenharmony_ci  CDB cdb;
664141cc406Sopenharmony_ci  SANE_Status status;
665141cc406Sopenharmony_ci  size_t size;
666141cc406Sopenharmony_ci  int i;
667141cc406Sopenharmony_ci
668141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_identify_scanner: enter\n");
669141cc406Sopenharmony_ci
670141cc406Sopenharmony_ci  size = 5;
671141cc406Sopenharmony_ci  MKSCSI_INQUIRY (cdb, size);
672141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
673141cc406Sopenharmony_ci			    NULL, 0, dev->buffer, &size);
674141cc406Sopenharmony_ci
675141cc406Sopenharmony_ci  if (status)
676141cc406Sopenharmony_ci    {
677141cc406Sopenharmony_ci      DBG (DBG_error,
678141cc406Sopenharmony_ci	   "matsushita_identify_scanner: inquiry failed with status %s\n",
679141cc406Sopenharmony_ci	   sane_strstatus (status));
680141cc406Sopenharmony_ci      return (SANE_FALSE);
681141cc406Sopenharmony_ci    }
682141cc406Sopenharmony_ci
683141cc406Sopenharmony_ci  size = dev->buffer[4] + 5;	/* total length of the inquiry data */
684141cc406Sopenharmony_ci
685141cc406Sopenharmony_ci  if (size < 36)
686141cc406Sopenharmony_ci    {
687141cc406Sopenharmony_ci      DBG (DBG_error,
688141cc406Sopenharmony_ci	   "matsushita_identify_scanner: not enough data to identify device\n");
689141cc406Sopenharmony_ci      return (SANE_FALSE);
690141cc406Sopenharmony_ci    }
691141cc406Sopenharmony_ci
692141cc406Sopenharmony_ci  MKSCSI_INQUIRY (cdb, size);
693141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
694141cc406Sopenharmony_ci			    NULL, 0, dev->buffer, &size);
695141cc406Sopenharmony_ci
696141cc406Sopenharmony_ci  if (status)
697141cc406Sopenharmony_ci    {
698141cc406Sopenharmony_ci      DBG (DBG_error,
699141cc406Sopenharmony_ci	   "matsushita_identify_scanner: inquiry failed with status %s\n",
700141cc406Sopenharmony_ci	   sane_strstatus (status));
701141cc406Sopenharmony_ci      return (SANE_FALSE);
702141cc406Sopenharmony_ci    }
703141cc406Sopenharmony_ci
704141cc406Sopenharmony_ci  hexdump (DBG_info2, "inquiry", dev->buffer, size);
705141cc406Sopenharmony_ci
706141cc406Sopenharmony_ci  dev->scsi_type = dev->buffer[0] & 0x1f;
707141cc406Sopenharmony_ci  memcpy (dev->scsi_vendor, dev->buffer + 0x08, 0x08);
708141cc406Sopenharmony_ci  dev->scsi_vendor[0x08] = 0;
709141cc406Sopenharmony_ci  memcpy (dev->scsi_product, dev->buffer + 0x10, 0x010);
710141cc406Sopenharmony_ci  dev->scsi_product[0x10] = 0;
711141cc406Sopenharmony_ci  memcpy (dev->scsi_version, dev->buffer + 0x20, 0x04);
712141cc406Sopenharmony_ci  dev->scsi_version[0x04] = 0;
713141cc406Sopenharmony_ci
714141cc406Sopenharmony_ci  DBG (DBG_info, "device is \"%s\" \"%s\" \"%s\"\n",
715141cc406Sopenharmony_ci       dev->scsi_vendor, dev->scsi_product, dev->scsi_version);
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci  /* Lookup through the supported scanners table to find if this
718141cc406Sopenharmony_ci   * backend supports that one. */
719141cc406Sopenharmony_ci  for (i = 0; i < NELEMS (scanners); i++)
720141cc406Sopenharmony_ci    {
721141cc406Sopenharmony_ci      if (dev->scsi_type == scanners[i].scsi_type &&
722141cc406Sopenharmony_ci	  strcmp (dev->scsi_vendor, scanners[i].scsi_vendor) == 0 &&
723141cc406Sopenharmony_ci	  strcmp (dev->scsi_product, scanners[i].scsi_product) == 0)
724141cc406Sopenharmony_ci	{
725141cc406Sopenharmony_ci
726141cc406Sopenharmony_ci	  DBG (DBG_error, "matsushita_identify_scanner: scanner supported\n");
727141cc406Sopenharmony_ci
728141cc406Sopenharmony_ci	  dev->scnum = i;
729141cc406Sopenharmony_ci
730141cc406Sopenharmony_ci	  return (SANE_TRUE);
731141cc406Sopenharmony_ci	}
732141cc406Sopenharmony_ci    }
733141cc406Sopenharmony_ci
734141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_identify_scanner: exit, device not supported\n");
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_ci  return (SANE_FALSE);
737141cc406Sopenharmony_ci}
738141cc406Sopenharmony_ci
739141cc406Sopenharmony_ci/* The interface can show different paper sizes. Show only the sizes
740141cc406Sopenharmony_ci * available for that scanner. */
741141cc406Sopenharmony_cistatic int
742141cc406Sopenharmony_cimatsushita_build_paper_sizes (Matsushita_Scanner * dev)
743141cc406Sopenharmony_ci{
744141cc406Sopenharmony_ci  SANE_String_Const *psl;	/* string list */
745141cc406Sopenharmony_ci  int *psv;			/* value list */
746141cc406Sopenharmony_ci  int num;
747141cc406Sopenharmony_ci  int i;
748141cc406Sopenharmony_ci
749141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_build_paper_sizes: enter\n");
750141cc406Sopenharmony_ci
751141cc406Sopenharmony_ci  psl = malloc ((sizeof (SANE_String_Const) + 1) * NELEMS (paper_sizes));
752141cc406Sopenharmony_ci  if (psl == NULL)
753141cc406Sopenharmony_ci    {
754141cc406Sopenharmony_ci      DBG (DBG_error, "ERROR: not enough memory\n");
755141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
756141cc406Sopenharmony_ci    }
757141cc406Sopenharmony_ci
758141cc406Sopenharmony_ci  psv = malloc ((sizeof (int) + 1) * NELEMS (paper_sizes));
759141cc406Sopenharmony_ci  if (psv == NULL)
760141cc406Sopenharmony_ci    {
761141cc406Sopenharmony_ci      DBG (DBG_error, "ERROR: not enough memory\n");
762141cc406Sopenharmony_ci      free (psl);
763141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
764141cc406Sopenharmony_ci    }
765141cc406Sopenharmony_ci
766141cc406Sopenharmony_ci  for (i = 0, num = 0; i < NELEMS (paper_sizes); i++)
767141cc406Sopenharmony_ci    {
768141cc406Sopenharmony_ci      if (SANE_UNFIX (scanners[dev->scnum].x_range.max) >=
769141cc406Sopenharmony_ci	  paper_sizes[i].width
770141cc406Sopenharmony_ci	  && SANE_UNFIX (scanners[dev->scnum].y_range.max) >=
771141cc406Sopenharmony_ci	  paper_sizes[i].length)
772141cc406Sopenharmony_ci	{
773141cc406Sopenharmony_ci
774141cc406Sopenharmony_ci	  /* This paper size fits into the scanner. */
775141cc406Sopenharmony_ci	  psl[num] = paper_sizes[i].name;
776141cc406Sopenharmony_ci	  psv[num] = i;
777141cc406Sopenharmony_ci	  num++;
778141cc406Sopenharmony_ci	}
779141cc406Sopenharmony_ci    }
780141cc406Sopenharmony_ci  psl[num] = NULL;		/* terminate the list */
781141cc406Sopenharmony_ci
782141cc406Sopenharmony_ci  dev->paper_sizes_list = psl;
783141cc406Sopenharmony_ci  dev->paper_sizes_val = psv;
784141cc406Sopenharmony_ci
785141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_build_paper_sizes: exit (%d)\n", num);
786141cc406Sopenharmony_ci
787141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
788141cc406Sopenharmony_ci}
789141cc406Sopenharmony_ci
790141cc406Sopenharmony_ci/* Lookup a string list from one array and return its index. */
791141cc406Sopenharmony_cistatic int
792141cc406Sopenharmony_ciget_string_list_index (SANE_String_Const list[], SANE_String_Const name)
793141cc406Sopenharmony_ci{
794141cc406Sopenharmony_ci  int index;
795141cc406Sopenharmony_ci
796141cc406Sopenharmony_ci  index = 0;
797141cc406Sopenharmony_ci  while (list[index] != NULL)
798141cc406Sopenharmony_ci    {
799141cc406Sopenharmony_ci      if (strcmp (list[index], name) == 0)
800141cc406Sopenharmony_ci	{
801141cc406Sopenharmony_ci	  return (index);
802141cc406Sopenharmony_ci	}
803141cc406Sopenharmony_ci      index++;
804141cc406Sopenharmony_ci    }
805141cc406Sopenharmony_ci
806141cc406Sopenharmony_ci  DBG (DBG_error, "name %s not found in list\n", name);
807141cc406Sopenharmony_ci
808141cc406Sopenharmony_ci  assert (0 == 1);		/* bug in backend, core dump */
809141cc406Sopenharmony_ci
810141cc406Sopenharmony_ci  return (-1);
811141cc406Sopenharmony_ci}
812141cc406Sopenharmony_ci
813141cc406Sopenharmony_ci/* Lookup an int list from one array and return its index. */
814141cc406Sopenharmony_cistatic int
815141cc406Sopenharmony_ciget_int_list_index (const SANE_Word list[], const SANE_Word value)
816141cc406Sopenharmony_ci{
817141cc406Sopenharmony_ci  int index;
818141cc406Sopenharmony_ci  int size;			/* number of elements */
819141cc406Sopenharmony_ci
820141cc406Sopenharmony_ci  index = 1;
821141cc406Sopenharmony_ci  size = list[0];
822141cc406Sopenharmony_ci  while (index <= size)
823141cc406Sopenharmony_ci    {
824141cc406Sopenharmony_ci      if (list[index] == value)
825141cc406Sopenharmony_ci	{
826141cc406Sopenharmony_ci	  return (index);
827141cc406Sopenharmony_ci	}
828141cc406Sopenharmony_ci      index++;
829141cc406Sopenharmony_ci    }
830141cc406Sopenharmony_ci
831141cc406Sopenharmony_ci  DBG (DBG_error, "word %d not found in list\n", value);
832141cc406Sopenharmony_ci
833141cc406Sopenharmony_ci  assert (0 == 1);		/* bug in backend, core dump */
834141cc406Sopenharmony_ci
835141cc406Sopenharmony_ci  return (-1);
836141cc406Sopenharmony_ci}
837141cc406Sopenharmony_ci
838141cc406Sopenharmony_ci/* SCSI sense handler. Callback for SANE. */
839141cc406Sopenharmony_cistatic SANE_Status
840141cc406Sopenharmony_cimatsushita_sense_handler (int scsi_fd, unsigned char *result, void __sane_unused__ *arg)
841141cc406Sopenharmony_ci{
842141cc406Sopenharmony_ci  int asc, ascq, sensekey;
843141cc406Sopenharmony_ci  int len;
844141cc406Sopenharmony_ci
845141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_sense_handler (scsi_fd = %d)\n", scsi_fd);
846141cc406Sopenharmony_ci
847141cc406Sopenharmony_ci  sensekey = get_RS_sense_key (result);
848141cc406Sopenharmony_ci  len = 7 + get_RS_additional_length (result);
849141cc406Sopenharmony_ci
850141cc406Sopenharmony_ci  hexdump (DBG_info2, "sense", result, len);
851141cc406Sopenharmony_ci
852141cc406Sopenharmony_ci  if (get_RS_error_code (result) != 0x70)
853141cc406Sopenharmony_ci    {
854141cc406Sopenharmony_ci      DBG (DBG_error,
855141cc406Sopenharmony_ci	   "matsushita_sense_handler: invalid sense key error code (%d)\n",
856141cc406Sopenharmony_ci	   get_RS_error_code (result));
857141cc406Sopenharmony_ci
858141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
859141cc406Sopenharmony_ci    }
860141cc406Sopenharmony_ci
861141cc406Sopenharmony_ci  if (get_RS_ILI (result) != 0)
862141cc406Sopenharmony_ci    {
863141cc406Sopenharmony_ci      DBG (DBG_sense, "matsushita_sense_handler: short read\n");
864141cc406Sopenharmony_ci    }
865141cc406Sopenharmony_ci
866141cc406Sopenharmony_ci  if (len < 14)
867141cc406Sopenharmony_ci    {
868141cc406Sopenharmony_ci      DBG (DBG_error,
869141cc406Sopenharmony_ci	   "matsushita_sense_handler: sense too short, no ASC/ASCQ\n");
870141cc406Sopenharmony_ci
871141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
872141cc406Sopenharmony_ci    }
873141cc406Sopenharmony_ci
874141cc406Sopenharmony_ci  asc = get_RS_ASC (result);
875141cc406Sopenharmony_ci  ascq = get_RS_ASCQ (result);
876141cc406Sopenharmony_ci
877141cc406Sopenharmony_ci  DBG (DBG_sense, "matsushita_sense_handler: sense=%d, ASC/ASCQ=%02x%02x\n",
878141cc406Sopenharmony_ci       sensekey, asc, ascq);
879141cc406Sopenharmony_ci
880141cc406Sopenharmony_ci  switch (sensekey)
881141cc406Sopenharmony_ci    {
882141cc406Sopenharmony_ci    case 0x00:			/* no sense */
883141cc406Sopenharmony_ci      if (get_RS_EOM (result) && asc == 0x00 && ascq == 0x00)
884141cc406Sopenharmony_ci	{
885141cc406Sopenharmony_ci	  DBG (DBG_sense, "matsushita_sense_handler: EOF\n");
886141cc406Sopenharmony_ci	  return SANE_STATUS_EOF;
887141cc406Sopenharmony_ci	}
888141cc406Sopenharmony_ci
889141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
890141cc406Sopenharmony_ci      break;
891141cc406Sopenharmony_ci
892141cc406Sopenharmony_ci    case 0x02:			/* not ready */
893141cc406Sopenharmony_ci      if (asc == 0x04 && ascq == 0x81)
894141cc406Sopenharmony_ci	{
895141cc406Sopenharmony_ci	  /* Jam door open. */
896141cc406Sopenharmony_ci	  return SANE_STATUS_COVER_OPEN;
897141cc406Sopenharmony_ci	}
898141cc406Sopenharmony_ci      break;
899141cc406Sopenharmony_ci
900141cc406Sopenharmony_ci    case 0x03:			/* medium error */
901141cc406Sopenharmony_ci      if (asc == 0x3a)
902141cc406Sopenharmony_ci	{
903141cc406Sopenharmony_ci	  /* No paper in the feeder. */
904141cc406Sopenharmony_ci	  return SANE_STATUS_NO_DOCS;
905141cc406Sopenharmony_ci	}
906141cc406Sopenharmony_ci      if (asc == 0x80)
907141cc406Sopenharmony_ci	{
908141cc406Sopenharmony_ci	  /* Probably a paper jam. ascq might give more info. */
909141cc406Sopenharmony_ci	  return SANE_STATUS_JAMMED;
910141cc406Sopenharmony_ci	}
911141cc406Sopenharmony_ci      break;
912141cc406Sopenharmony_ci
913141cc406Sopenharmony_ci    case 0x05:
914141cc406Sopenharmony_ci      if (asc == 0x20 || asc == 0x24 || asc == 0x26)
915141cc406Sopenharmony_ci	{
916141cc406Sopenharmony_ci	  /* Invalid command, invalid field in CDB or invalid field in data.
917141cc406Sopenharmony_ci	   * The backend has prepared some wrong combination of options.
918141cc406Sopenharmony_ci	   * Shot the backend maintainer. */
919141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
920141cc406Sopenharmony_ci	}
921141cc406Sopenharmony_ci      else if (asc == 0x2c && ascq == 0x80)
922141cc406Sopenharmony_ci	{
923141cc406Sopenharmony_ci	  /* The scanner does have enough memory to scan the whole
924141cc406Sopenharmony_ci	   * area. For instance the KV-SS25 has only 4MB of memory,
925141cc406Sopenharmony_ci	   * which is not enough to scan a A4 page at 300dpi in gray
926141cc406Sopenharmony_ci	   * 8 bits. */
927141cc406Sopenharmony_ci	  return SANE_STATUS_NO_MEM;
928141cc406Sopenharmony_ci	}
929141cc406Sopenharmony_ci      break;
930141cc406Sopenharmony_ci
931141cc406Sopenharmony_ci    case 0x06:
932141cc406Sopenharmony_ci      if (asc == 0x29)
933141cc406Sopenharmony_ci	{
934141cc406Sopenharmony_ci	  /* Reset occurred. May be the backend should retry the
935141cc406Sopenharmony_ci	   * command. */
936141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
937141cc406Sopenharmony_ci	}
938141cc406Sopenharmony_ci      break;
939141cc406Sopenharmony_ci    }
940141cc406Sopenharmony_ci
941141cc406Sopenharmony_ci  DBG (DBG_sense,
942141cc406Sopenharmony_ci       "matsushita_sense_handler: unknown error condition. Please report it to the backend maintainer\n");
943141cc406Sopenharmony_ci
944141cc406Sopenharmony_ci  return SANE_STATUS_IO_ERROR;
945141cc406Sopenharmony_ci}
946141cc406Sopenharmony_ci
947141cc406Sopenharmony_ci/* Check that a new page is available by issuing an empty read. The
948141cc406Sopenharmony_ci * sense handler might return SANE_STATUS_NO_DOCS which indicates that
949141cc406Sopenharmony_ci * the feeder is now empty. */
950141cc406Sopenharmony_cistatic SANE_Status
951141cc406Sopenharmony_cimatsushita_check_next_page (Matsushita_Scanner * dev)
952141cc406Sopenharmony_ci{
953141cc406Sopenharmony_ci  CDB cdb;
954141cc406Sopenharmony_ci  SANE_Status status;
955141cc406Sopenharmony_ci
956141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_check_next_page: enter\n");
957141cc406Sopenharmony_ci
958141cc406Sopenharmony_ci  MKSCSI_READ_10 (cdb, 0, 0, 0);
959141cc406Sopenharmony_ci  cdb.data[4] = dev->page_num;	/* May be cdb.data[3] too? */
960141cc406Sopenharmony_ci  cdb.data[5] = dev->page_side;
961141cc406Sopenharmony_ci
962141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len, NULL, 0, NULL, NULL);
963141cc406Sopenharmony_ci
964141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_check_next_page: exit with status %d\n", status);
965141cc406Sopenharmony_ci
966141cc406Sopenharmony_ci  return (status);
967141cc406Sopenharmony_ci}
968141cc406Sopenharmony_ci
969141cc406Sopenharmony_ci/* Attach a scanner to this backend. */
970141cc406Sopenharmony_cistatic SANE_Status
971141cc406Sopenharmony_ciattach_scanner (const char *devicename, Matsushita_Scanner ** devp)
972141cc406Sopenharmony_ci{
973141cc406Sopenharmony_ci  Matsushita_Scanner *dev;
974141cc406Sopenharmony_ci  int sfd;
975141cc406Sopenharmony_ci
976141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "attach_scanner: %s\n", devicename);
977141cc406Sopenharmony_ci
978141cc406Sopenharmony_ci  if (devp)
979141cc406Sopenharmony_ci    *devp = NULL;
980141cc406Sopenharmony_ci
981141cc406Sopenharmony_ci  /* Check if we know this device name. */
982141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
983141cc406Sopenharmony_ci    {
984141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devicename) == 0)
985141cc406Sopenharmony_ci	{
986141cc406Sopenharmony_ci	  if (devp)
987141cc406Sopenharmony_ci	    {
988141cc406Sopenharmony_ci	      *devp = dev;
989141cc406Sopenharmony_ci	    }
990141cc406Sopenharmony_ci	  DBG (DBG_info, "device is already known\n");
991141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
992141cc406Sopenharmony_ci	}
993141cc406Sopenharmony_ci    }
994141cc406Sopenharmony_ci
995141cc406Sopenharmony_ci  /* Allocate a new scanner entry. */
996141cc406Sopenharmony_ci  dev = matsushita_init ();
997141cc406Sopenharmony_ci  if (dev == NULL)
998141cc406Sopenharmony_ci    {
999141cc406Sopenharmony_ci      DBG (DBG_error, "ERROR: not enough memory\n");
1000141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1001141cc406Sopenharmony_ci    }
1002141cc406Sopenharmony_ci
1003141cc406Sopenharmony_ci  DBG (DBG_info, "attach_scanner: opening %s\n", devicename);
1004141cc406Sopenharmony_ci
1005141cc406Sopenharmony_ci  if (sanei_scsi_open (devicename, &sfd, matsushita_sense_handler, dev) != 0)
1006141cc406Sopenharmony_ci    {
1007141cc406Sopenharmony_ci      DBG (DBG_error, "ERROR: attach_scanner: open failed\n");
1008141cc406Sopenharmony_ci      matsushita_free (dev);
1009141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1010141cc406Sopenharmony_ci    }
1011141cc406Sopenharmony_ci
1012141cc406Sopenharmony_ci  /* Fill some scanner specific values. */
1013141cc406Sopenharmony_ci  dev->devicename = strdup (devicename);
1014141cc406Sopenharmony_ci  dev->sfd = sfd;
1015141cc406Sopenharmony_ci
1016141cc406Sopenharmony_ci  /* Now, check that it is a scanner we support. */
1017141cc406Sopenharmony_ci  if (matsushita_identify_scanner (dev) == SANE_FALSE)
1018141cc406Sopenharmony_ci    {
1019141cc406Sopenharmony_ci      DBG (DBG_error,
1020141cc406Sopenharmony_ci	   "ERROR: attach_scanner: scanner-identification failed\n");
1021141cc406Sopenharmony_ci      matsushita_free (dev);
1022141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1023141cc406Sopenharmony_ci    }
1024141cc406Sopenharmony_ci
1025141cc406Sopenharmony_ci  matsushita_close (dev);
1026141cc406Sopenharmony_ci
1027141cc406Sopenharmony_ci  /* Set the default options for that scanner. */
1028141cc406Sopenharmony_ci  dev->sane.name = dev->devicename;
1029141cc406Sopenharmony_ci  dev->sane.vendor = "Panasonic";
1030141cc406Sopenharmony_ci  dev->sane.model = dev->scsi_product;
1031141cc406Sopenharmony_ci  dev->sane.type = SANE_I18N ("sheetfed scanner");
1032141cc406Sopenharmony_ci
1033141cc406Sopenharmony_ci  /* Link the scanner with the others. */
1034141cc406Sopenharmony_ci  dev->next = first_dev;
1035141cc406Sopenharmony_ci  first_dev = dev;
1036141cc406Sopenharmony_ci
1037141cc406Sopenharmony_ci  if (devp)
1038141cc406Sopenharmony_ci    {
1039141cc406Sopenharmony_ci      *devp = dev;
1040141cc406Sopenharmony_ci    }
1041141cc406Sopenharmony_ci
1042141cc406Sopenharmony_ci  num_devices++;
1043141cc406Sopenharmony_ci
1044141cc406Sopenharmony_ci  DBG (DBG_proc, "attach_scanner: exit\n");
1045141cc406Sopenharmony_ci
1046141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1047141cc406Sopenharmony_ci}
1048141cc406Sopenharmony_ci
1049141cc406Sopenharmony_cistatic SANE_Status
1050141cc406Sopenharmony_ciattach_one (const char *dev)
1051141cc406Sopenharmony_ci{
1052141cc406Sopenharmony_ci  attach_scanner (dev, NULL);
1053141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1054141cc406Sopenharmony_ci}
1055141cc406Sopenharmony_ci
1056141cc406Sopenharmony_ci/* Reset the options for that scanner. */
1057141cc406Sopenharmony_cistatic void
1058141cc406Sopenharmony_cimatsushita_init_options (Matsushita_Scanner * dev)
1059141cc406Sopenharmony_ci{
1060141cc406Sopenharmony_ci  int i;
1061141cc406Sopenharmony_ci
1062141cc406Sopenharmony_ci  /* Pre-initialize the options. */
1063141cc406Sopenharmony_ci  memset (dev->opt, 0, sizeof (dev->opt));
1064141cc406Sopenharmony_ci  memset (dev->val, 0, sizeof (dev->val));
1065141cc406Sopenharmony_ci
1066141cc406Sopenharmony_ci  for (i = 0; i < OPT_NUM_OPTIONS; ++i)
1067141cc406Sopenharmony_ci    {
1068141cc406Sopenharmony_ci      dev->opt[i].size = sizeof (SANE_Word);
1069141cc406Sopenharmony_ci      dev->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1070141cc406Sopenharmony_ci    }
1071141cc406Sopenharmony_ci
1072141cc406Sopenharmony_ci  /* Number of options. */
1073141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].name = "";
1074141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
1075141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
1076141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
1077141cc406Sopenharmony_ci  dev->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
1078141cc406Sopenharmony_ci  dev->val[OPT_NUM_OPTS].w = OPT_NUM_OPTIONS;
1079141cc406Sopenharmony_ci
1080141cc406Sopenharmony_ci  /* Mode group */
1081141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode");
1082141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].desc = "";	/* not valid for a group */
1083141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
1084141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].cap = 0;
1085141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].size = 0;
1086141cc406Sopenharmony_ci  dev->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1087141cc406Sopenharmony_ci
1088141cc406Sopenharmony_ci  /* Scanner supported modes */
1089141cc406Sopenharmony_ci  dev->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
1090141cc406Sopenharmony_ci  dev->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
1091141cc406Sopenharmony_ci  dev->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
1092141cc406Sopenharmony_ci  dev->opt[OPT_MODE].type = SANE_TYPE_STRING;
1093141cc406Sopenharmony_ci  dev->opt[OPT_MODE].size =
1094141cc406Sopenharmony_ci    max_string_size (scanners[dev->scnum].scan_mode_list);
1095141cc406Sopenharmony_ci  dev->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1096141cc406Sopenharmony_ci  dev->opt[OPT_MODE].constraint.string_list =
1097141cc406Sopenharmony_ci    scanners[dev->scnum].scan_mode_list;
1098141cc406Sopenharmony_ci  dev->val[OPT_MODE].s = (SANE_Char *) strdup ("");	/* will be set later */
1099141cc406Sopenharmony_ci
1100141cc406Sopenharmony_ci  /* X and Y resolution */
1101141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
1102141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
1103141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
1104141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
1105141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
1106141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
1107141cc406Sopenharmony_ci  dev->opt[OPT_RESOLUTION].constraint.word_list =
1108141cc406Sopenharmony_ci    scanners[dev->scnum].resolutions_list;
1109141cc406Sopenharmony_ci  dev->val[OPT_RESOLUTION].w = resolutions_list_300[1];
1110141cc406Sopenharmony_ci
1111141cc406Sopenharmony_ci  /* Duplex */
1112141cc406Sopenharmony_ci  dev->opt[OPT_DUPLEX].name = SANE_NAME_DUPLEX;
1113141cc406Sopenharmony_ci  dev->opt[OPT_DUPLEX].title = SANE_TITLE_DUPLEX;
1114141cc406Sopenharmony_ci  dev->opt[OPT_DUPLEX].desc = SANE_DESC_DUPLEX;
1115141cc406Sopenharmony_ci  dev->opt[OPT_DUPLEX].type = SANE_TYPE_BOOL;
1116141cc406Sopenharmony_ci  dev->opt[OPT_DUPLEX].unit = SANE_UNIT_NONE;
1117141cc406Sopenharmony_ci  dev->val[OPT_DUPLEX].w = SANE_FALSE;
1118141cc406Sopenharmony_ci  if ((scanners[dev->scnum].cap & MAT_CAP_DUPLEX) == 0)
1119141cc406Sopenharmony_ci    dev->opt[OPT_DUPLEX].cap |= SANE_CAP_INACTIVE;
1120141cc406Sopenharmony_ci
1121141cc406Sopenharmony_ci  /* Feeder mode */
1122141cc406Sopenharmony_ci  dev->opt[OPT_FEEDER_MODE].name = "feeder-mode";
1123141cc406Sopenharmony_ci  dev->opt[OPT_FEEDER_MODE].title = SANE_I18N ("Feeder mode");
1124141cc406Sopenharmony_ci  dev->opt[OPT_FEEDER_MODE].desc = SANE_I18N ("Sets the feeding mode");
1125141cc406Sopenharmony_ci  dev->opt[OPT_FEEDER_MODE].type = SANE_TYPE_STRING;
1126141cc406Sopenharmony_ci  dev->opt[OPT_FEEDER_MODE].size = max_string_size (feeder_mode_list);
1127141cc406Sopenharmony_ci  dev->opt[OPT_FEEDER_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1128141cc406Sopenharmony_ci  dev->opt[OPT_FEEDER_MODE].constraint.string_list = feeder_mode_list;
1129141cc406Sopenharmony_ci  dev->val[OPT_FEEDER_MODE].s = strdup (feeder_mode_list[0]);
1130141cc406Sopenharmony_ci
1131141cc406Sopenharmony_ci  /* Geometry group */
1132141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry");
1133141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].desc = "";	/* not valid for a group */
1134141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
1135141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].cap = 0;
1136141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].size = 0;
1137141cc406Sopenharmony_ci  dev->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1138141cc406Sopenharmony_ci
1139141cc406Sopenharmony_ci  /* Paper sizes list. */
1140141cc406Sopenharmony_ci  dev->opt[OPT_PAPER_SIZE].name = SANE_NAME_PAPER_SIZE;
1141141cc406Sopenharmony_ci  dev->opt[OPT_PAPER_SIZE].title = SANE_TITLE_PAPER_SIZE;
1142141cc406Sopenharmony_ci  dev->opt[OPT_PAPER_SIZE].desc = SANE_DESC_PAPER_SIZE;
1143141cc406Sopenharmony_ci  dev->opt[OPT_PAPER_SIZE].type = SANE_TYPE_STRING;
1144141cc406Sopenharmony_ci  dev->opt[OPT_PAPER_SIZE].size = max_string_size (dev->paper_sizes_list);
1145141cc406Sopenharmony_ci  dev->opt[OPT_PAPER_SIZE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1146141cc406Sopenharmony_ci  dev->opt[OPT_PAPER_SIZE].constraint.string_list = dev->paper_sizes_list;
1147141cc406Sopenharmony_ci  dev->val[OPT_PAPER_SIZE].s = strdup ("");	/* will do it later */
1148141cc406Sopenharmony_ci
1149141cc406Sopenharmony_ci  /* Upper left X */
1150141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
1151141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
1152141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
1153141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
1154141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].unit = SANE_UNIT_MM;
1155141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
1156141cc406Sopenharmony_ci  dev->opt[OPT_TL_X].constraint.range = &(scanners[dev->scnum].x_range);
1157141cc406Sopenharmony_ci
1158141cc406Sopenharmony_ci  /* Upper left Y */
1159141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
1160141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
1161141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
1162141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
1163141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
1164141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1165141cc406Sopenharmony_ci  dev->opt[OPT_TL_Y].constraint.range = &(scanners[dev->scnum].y_range);
1166141cc406Sopenharmony_ci
1167141cc406Sopenharmony_ci  /* Bottom-right x */
1168141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
1169141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
1170141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
1171141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
1172141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].unit = SANE_UNIT_MM;
1173141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
1174141cc406Sopenharmony_ci  dev->opt[OPT_BR_X].constraint.range = &(scanners[dev->scnum].x_range);
1175141cc406Sopenharmony_ci
1176141cc406Sopenharmony_ci  /* Bottom-right y */
1177141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
1178141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
1179141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
1180141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
1181141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
1182141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1183141cc406Sopenharmony_ci  dev->opt[OPT_BR_Y].constraint.range = &(scanners[dev->scnum].y_range);
1184141cc406Sopenharmony_ci
1185141cc406Sopenharmony_ci  /* Enhancement group */
1186141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement");
1187141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].desc = "";	/* not valid for a group */
1188141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
1189141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED;
1190141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].size = 0;
1191141cc406Sopenharmony_ci  dev->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1192141cc406Sopenharmony_ci
1193141cc406Sopenharmony_ci  /* Brightness */
1194141cc406Sopenharmony_ci  dev->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
1195141cc406Sopenharmony_ci  dev->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
1196141cc406Sopenharmony_ci  dev->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
1197141cc406Sopenharmony_ci  dev->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
1198141cc406Sopenharmony_ci  dev->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
1199141cc406Sopenharmony_ci  dev->opt[OPT_BRIGHTNESS].size = sizeof (SANE_Int);
1200141cc406Sopenharmony_ci  dev->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
1201141cc406Sopenharmony_ci  dev->opt[OPT_BRIGHTNESS].constraint.range =
1202141cc406Sopenharmony_ci    &(scanners[dev->scnum].brightness_range);
1203141cc406Sopenharmony_ci  dev->val[OPT_BRIGHTNESS].w = 128;
1204141cc406Sopenharmony_ci
1205141cc406Sopenharmony_ci  /* Contrast */
1206141cc406Sopenharmony_ci  dev->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
1207141cc406Sopenharmony_ci  dev->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
1208141cc406Sopenharmony_ci  dev->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
1209141cc406Sopenharmony_ci  dev->opt[OPT_CONTRAST].type = SANE_TYPE_INT;
1210141cc406Sopenharmony_ci  dev->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE;
1211141cc406Sopenharmony_ci  dev->opt[OPT_CONTRAST].size = sizeof (SANE_Int);
1212141cc406Sopenharmony_ci  dev->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
1213141cc406Sopenharmony_ci  dev->opt[OPT_CONTRAST].constraint.range =
1214141cc406Sopenharmony_ci    &(scanners[dev->scnum].contrast_range);
1215141cc406Sopenharmony_ci  dev->val[OPT_CONTRAST].w = 128;
1216141cc406Sopenharmony_ci  if ((scanners[dev->scnum].cap & MAT_CAP_CONTRAST) == 0)
1217141cc406Sopenharmony_ci    dev->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
1218141cc406Sopenharmony_ci
1219141cc406Sopenharmony_ci  /* Automatic threshold */
1220141cc406Sopenharmony_ci  dev->opt[OPT_AUTOMATIC_THRESHOLD].name = "automatic-threshold";
1221141cc406Sopenharmony_ci  dev->opt[OPT_AUTOMATIC_THRESHOLD].title = SANE_I18N ("Automatic threshold");
1222141cc406Sopenharmony_ci  dev->opt[OPT_AUTOMATIC_THRESHOLD].desc =
1223141cc406Sopenharmony_ci    SANE_I18N
1224141cc406Sopenharmony_ci    ("Automatically sets brightness, contrast, white level, gamma, noise reduction and image emphasis");
1225141cc406Sopenharmony_ci  dev->opt[OPT_AUTOMATIC_THRESHOLD].type = SANE_TYPE_STRING;
1226141cc406Sopenharmony_ci  dev->opt[OPT_AUTOMATIC_THRESHOLD].size =
1227141cc406Sopenharmony_ci    max_string_size (automatic_threshold_list);
1228141cc406Sopenharmony_ci  dev->opt[OPT_AUTOMATIC_THRESHOLD].constraint_type =
1229141cc406Sopenharmony_ci    SANE_CONSTRAINT_STRING_LIST;
1230141cc406Sopenharmony_ci  dev->opt[OPT_AUTOMATIC_THRESHOLD].constraint.string_list =
1231141cc406Sopenharmony_ci    automatic_threshold_list;
1232141cc406Sopenharmony_ci  dev->val[OPT_AUTOMATIC_THRESHOLD].s = strdup (automatic_threshold_list[0]);
1233141cc406Sopenharmony_ci  if ((scanners[dev->scnum].cap & MAT_CAP_AUTOMATIC_THRESHOLD) == 0)
1234141cc406Sopenharmony_ci    dev->opt[OPT_AUTOMATIC_THRESHOLD].cap |= SANE_CAP_INACTIVE;
1235141cc406Sopenharmony_ci
1236141cc406Sopenharmony_ci  /* Halftone pattern */
1237141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN;
1238141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN;
1239141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN;
1240141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_STRING;
1241141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].size =
1242141cc406Sopenharmony_ci    max_string_size (halftone_pattern_list);
1243141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
1244141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].constraint_type =
1245141cc406Sopenharmony_ci    SANE_CONSTRAINT_STRING_LIST;
1246141cc406Sopenharmony_ci  dev->opt[OPT_HALFTONE_PATTERN].constraint.string_list =
1247141cc406Sopenharmony_ci    halftone_pattern_list;
1248141cc406Sopenharmony_ci  dev->val[OPT_HALFTONE_PATTERN].s = strdup (halftone_pattern_list[0]);
1249141cc406Sopenharmony_ci
1250141cc406Sopenharmony_ci  /* Automatic separation */
1251141cc406Sopenharmony_ci  dev->opt[OPT_AUTOMATIC_SEPARATION].name = SANE_NAME_AUTOSEP;
1252141cc406Sopenharmony_ci  dev->opt[OPT_AUTOMATIC_SEPARATION].title = SANE_TITLE_AUTOSEP;
1253141cc406Sopenharmony_ci  dev->opt[OPT_AUTOMATIC_SEPARATION].desc = SANE_DESC_AUTOSEP;
1254141cc406Sopenharmony_ci  dev->opt[OPT_AUTOMATIC_SEPARATION].type = SANE_TYPE_BOOL;
1255141cc406Sopenharmony_ci  dev->opt[OPT_AUTOMATIC_SEPARATION].unit = SANE_UNIT_NONE;
1256141cc406Sopenharmony_ci  dev->val[OPT_AUTOMATIC_SEPARATION].w = SANE_FALSE;
1257141cc406Sopenharmony_ci
1258141cc406Sopenharmony_ci  /* White level base */
1259141cc406Sopenharmony_ci  dev->opt[OPT_WHITE_LEVEL].name = SANE_NAME_WHITE_LEVEL;
1260141cc406Sopenharmony_ci  dev->opt[OPT_WHITE_LEVEL].title = SANE_TITLE_WHITE_LEVEL;
1261141cc406Sopenharmony_ci  dev->opt[OPT_WHITE_LEVEL].desc = SANE_DESC_WHITE_LEVEL;
1262141cc406Sopenharmony_ci  dev->opt[OPT_WHITE_LEVEL].type = SANE_TYPE_STRING;
1263141cc406Sopenharmony_ci  dev->opt[OPT_WHITE_LEVEL].size = max_string_size (white_level_list);
1264141cc406Sopenharmony_ci  dev->opt[OPT_WHITE_LEVEL].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1265141cc406Sopenharmony_ci  dev->opt[OPT_WHITE_LEVEL].constraint.string_list = white_level_list;
1266141cc406Sopenharmony_ci  dev->val[OPT_WHITE_LEVEL].s = strdup (white_level_list[0]);
1267141cc406Sopenharmony_ci  if ((scanners[dev->scnum].cap & MAT_CAP_WHITE_LEVEL) == 0)
1268141cc406Sopenharmony_ci    dev->opt[OPT_WHITE_LEVEL].cap |= SANE_CAP_INACTIVE;
1269141cc406Sopenharmony_ci
1270141cc406Sopenharmony_ci  /* Noise reduction */
1271141cc406Sopenharmony_ci  dev->opt[OPT_NOISE_REDUCTION].name = "noise-reduction";
1272141cc406Sopenharmony_ci  dev->opt[OPT_NOISE_REDUCTION].title = SANE_I18N ("Noise reduction");
1273141cc406Sopenharmony_ci  dev->opt[OPT_NOISE_REDUCTION].desc =
1274141cc406Sopenharmony_ci    SANE_I18N ("Reduce the isolated dot noise");
1275141cc406Sopenharmony_ci  dev->opt[OPT_NOISE_REDUCTION].type = SANE_TYPE_STRING;
1276141cc406Sopenharmony_ci  dev->opt[OPT_NOISE_REDUCTION].size = max_string_size (noise_reduction_list);
1277141cc406Sopenharmony_ci  dev->opt[OPT_NOISE_REDUCTION].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1278141cc406Sopenharmony_ci  dev->opt[OPT_NOISE_REDUCTION].constraint.string_list = noise_reduction_list;
1279141cc406Sopenharmony_ci  dev->val[OPT_NOISE_REDUCTION].s = strdup (noise_reduction_list[0]);
1280141cc406Sopenharmony_ci  if ((scanners[dev->scnum].cap & MAT_CAP_NOISE_REDUCTION) == 0)
1281141cc406Sopenharmony_ci    dev->opt[OPT_NOISE_REDUCTION].cap |= SANE_CAP_INACTIVE;
1282141cc406Sopenharmony_ci
1283141cc406Sopenharmony_ci  /* Image emphasis */
1284141cc406Sopenharmony_ci  dev->opt[OPT_IMAGE_EMPHASIS].name = "image-emphasis";
1285141cc406Sopenharmony_ci  dev->opt[OPT_IMAGE_EMPHASIS].title = SANE_I18N ("Image emphasis");
1286141cc406Sopenharmony_ci  dev->opt[OPT_IMAGE_EMPHASIS].desc = SANE_I18N ("Sets the image emphasis");
1287141cc406Sopenharmony_ci  dev->opt[OPT_IMAGE_EMPHASIS].type = SANE_TYPE_STRING;
1288141cc406Sopenharmony_ci  dev->opt[OPT_IMAGE_EMPHASIS].size =
1289141cc406Sopenharmony_ci    max_string_size (scanners[dev->scnum].image_emphasis_list);
1290141cc406Sopenharmony_ci  dev->opt[OPT_IMAGE_EMPHASIS].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1291141cc406Sopenharmony_ci  dev->opt[OPT_IMAGE_EMPHASIS].constraint.string_list =
1292141cc406Sopenharmony_ci    scanners[dev->scnum].image_emphasis_list;
1293141cc406Sopenharmony_ci  dev->val[OPT_IMAGE_EMPHASIS].s = strdup (SANE_I18N ("Medium"));
1294141cc406Sopenharmony_ci
1295141cc406Sopenharmony_ci  /* Gamma */
1296141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA].name = "gamma";
1297141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA].title = SANE_I18N ("Gamma");
1298141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA].desc = SANE_I18N ("Gamma");
1299141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA].type = SANE_TYPE_STRING;
1300141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA].size = max_string_size (gamma_list);
1301141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1302141cc406Sopenharmony_ci  dev->opt[OPT_GAMMA].constraint.string_list = gamma_list;
1303141cc406Sopenharmony_ci  dev->val[OPT_GAMMA].s = strdup (gamma_list[0]);
1304141cc406Sopenharmony_ci
1305141cc406Sopenharmony_ci  /* Lastly, set the default scan mode. This might change some
1306141cc406Sopenharmony_ci   * values previously set here. */
1307141cc406Sopenharmony_ci  sane_control_option (dev, OPT_PAPER_SIZE, SANE_ACTION_SET_VALUE,
1308141cc406Sopenharmony_ci		       (SANE_String_Const *) dev->paper_sizes_list[0], NULL);
1309141cc406Sopenharmony_ci  sane_control_option (dev, OPT_MODE, SANE_ACTION_SET_VALUE,
1310141cc406Sopenharmony_ci		       (SANE_String_Const *) scanners[dev->scnum].
1311141cc406Sopenharmony_ci		       scan_mode_list[0], NULL);
1312141cc406Sopenharmony_ci}
1313141cc406Sopenharmony_ci
1314141cc406Sopenharmony_ci/* Wait until the scanner is ready.
1315141cc406Sopenharmony_ci *
1316141cc406Sopenharmony_ci * The only reason I know the scanner is not ready is because it is
1317141cc406Sopenharmony_ci * moving the CCD.
1318141cc406Sopenharmony_ci */
1319141cc406Sopenharmony_cistatic SANE_Status
1320141cc406Sopenharmony_cimatsushita_wait_scanner (Matsushita_Scanner * dev)
1321141cc406Sopenharmony_ci{
1322141cc406Sopenharmony_ci  SANE_Status status;
1323141cc406Sopenharmony_ci  int timeout;
1324141cc406Sopenharmony_ci  CDB cdb;
1325141cc406Sopenharmony_ci
1326141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_wait_scanner: enter\n");
1327141cc406Sopenharmony_ci
1328141cc406Sopenharmony_ci  MKSCSI_TEST_UNIT_READY (cdb);
1329141cc406Sopenharmony_ci
1330141cc406Sopenharmony_ci  /* Set the timeout to 60 seconds. */
1331141cc406Sopenharmony_ci  timeout = 60;
1332141cc406Sopenharmony_ci
1333141cc406Sopenharmony_ci  while (timeout > 0)
1334141cc406Sopenharmony_ci    {
1335141cc406Sopenharmony_ci
1336141cc406Sopenharmony_ci      /* test unit ready */
1337141cc406Sopenharmony_ci      status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
1338141cc406Sopenharmony_ci				NULL, 0, NULL, NULL);
1339141cc406Sopenharmony_ci
1340141cc406Sopenharmony_ci      if (status == SANE_STATUS_GOOD)
1341141cc406Sopenharmony_ci	{
1342141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1343141cc406Sopenharmony_ci	}
1344141cc406Sopenharmony_ci
1345141cc406Sopenharmony_ci      sleep (1);
1346141cc406Sopenharmony_ci    };
1347141cc406Sopenharmony_ci
1348141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_wait_scanner: scanner not ready\n");
1349141cc406Sopenharmony_ci  return (SANE_STATUS_IO_ERROR);
1350141cc406Sopenharmony_ci}
1351141cc406Sopenharmony_ci
1352141cc406Sopenharmony_ci/* Reset a window. This is used to re-initialize the scanner. */
1353141cc406Sopenharmony_cistatic SANE_Status
1354141cc406Sopenharmony_cimatsushita_reset_window (Matsushita_Scanner * dev)
1355141cc406Sopenharmony_ci{
1356141cc406Sopenharmony_ci  CDB cdb;
1357141cc406Sopenharmony_ci  SANE_Status status;
1358141cc406Sopenharmony_ci
1359141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_reset_window: enter\n");
1360141cc406Sopenharmony_ci
1361141cc406Sopenharmony_ci  MKSCSI_SET_WINDOW (cdb, 0);
1362141cc406Sopenharmony_ci
1363141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len, NULL, 0, NULL, NULL);
1364141cc406Sopenharmony_ci
1365141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_reset_window: exit, status=%d\n", status);
1366141cc406Sopenharmony_ci
1367141cc406Sopenharmony_ci  return status;
1368141cc406Sopenharmony_ci}
1369141cc406Sopenharmony_ci
1370141cc406Sopenharmony_ci/* Set a window. */
1371141cc406Sopenharmony_cistatic SANE_Status
1372141cc406Sopenharmony_cimatsushita_set_window (Matsushita_Scanner * dev, int side)
1373141cc406Sopenharmony_ci{
1374141cc406Sopenharmony_ci  size_t size;
1375141cc406Sopenharmony_ci  CDB cdb;
1376141cc406Sopenharmony_ci  unsigned char window[72];
1377141cc406Sopenharmony_ci  SANE_Status status;
1378141cc406Sopenharmony_ci  int i;
1379141cc406Sopenharmony_ci
1380141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_set_window: enter\n");
1381141cc406Sopenharmony_ci
1382141cc406Sopenharmony_ci  size = sizeof (window);
1383141cc406Sopenharmony_ci  MKSCSI_SET_WINDOW (cdb, size);
1384141cc406Sopenharmony_ci
1385141cc406Sopenharmony_ci  memset (window, 0, size);
1386141cc406Sopenharmony_ci
1387141cc406Sopenharmony_ci  /* size of the windows descriptor block */
1388141cc406Sopenharmony_ci  window[7] = sizeof (window) - 8;
1389141cc406Sopenharmony_ci
1390141cc406Sopenharmony_ci  /* Page side */
1391141cc406Sopenharmony_ci  window[8] = side;
1392141cc406Sopenharmony_ci
1393141cc406Sopenharmony_ci  /* X and Y resolution */
1394141cc406Sopenharmony_ci  Ito16 (dev->resolution, &window[10]);
1395141cc406Sopenharmony_ci  Ito16 (dev->resolution, &window[12]);
1396141cc406Sopenharmony_ci
1397141cc406Sopenharmony_ci  /* Upper Left (X,Y) */
1398141cc406Sopenharmony_ci  Ito32 (dev->x_tl, &window[14]);
1399141cc406Sopenharmony_ci  Ito32 (dev->y_tl, &window[18]);
1400141cc406Sopenharmony_ci
1401141cc406Sopenharmony_ci  /* Width and length */
1402141cc406Sopenharmony_ci  Ito32 (dev->width, &window[22]);
1403141cc406Sopenharmony_ci  Ito32 (dev->length, &window[26]);
1404141cc406Sopenharmony_ci  Ito32 (dev->width, &window[56]);	/* again, verso? */
1405141cc406Sopenharmony_ci  Ito32 (dev->length, &window[60]);	/* again, verso? */
1406141cc406Sopenharmony_ci
1407141cc406Sopenharmony_ci  /* Brightness */
1408141cc406Sopenharmony_ci  window[30] = 255 - dev->val[OPT_BRIGHTNESS].w;
1409141cc406Sopenharmony_ci  window[31] = window[30];	/* same as brightness. */
1410141cc406Sopenharmony_ci
1411141cc406Sopenharmony_ci  /* Contrast */
1412141cc406Sopenharmony_ci  window[32] = dev->val[OPT_CONTRAST].w;
1413141cc406Sopenharmony_ci
1414141cc406Sopenharmony_ci  /* Image Composition */
1415141cc406Sopenharmony_ci  switch (dev->scan_mode)
1416141cc406Sopenharmony_ci    {
1417141cc406Sopenharmony_ci    case MATSUSHITA_BW:
1418141cc406Sopenharmony_ci      window[33] = 0x00;
1419141cc406Sopenharmony_ci      break;
1420141cc406Sopenharmony_ci    case MATSUSHITA_HALFTONE:
1421141cc406Sopenharmony_ci      window[33] = 0x01;
1422141cc406Sopenharmony_ci      break;
1423141cc406Sopenharmony_ci    case MATSUSHITA_GRAYSCALE:
1424141cc406Sopenharmony_ci      window[33] = 0x02;
1425141cc406Sopenharmony_ci      break;
1426141cc406Sopenharmony_ci    }
1427141cc406Sopenharmony_ci
1428141cc406Sopenharmony_ci  /* Depth */
1429141cc406Sopenharmony_ci  window[34] = dev->depth;
1430141cc406Sopenharmony_ci
1431141cc406Sopenharmony_ci  /* Halftone pattern. */
1432141cc406Sopenharmony_ci  if (dev->scan_mode == MATSUSHITA_HALFTONE)
1433141cc406Sopenharmony_ci    {
1434141cc406Sopenharmony_ci      i = get_string_list_index (halftone_pattern_list,
1435141cc406Sopenharmony_ci				 dev->val[OPT_HALFTONE_PATTERN].s);
1436141cc406Sopenharmony_ci      window[36] = halftone_pattern_val[i];
1437141cc406Sopenharmony_ci    }
1438141cc406Sopenharmony_ci
1439141cc406Sopenharmony_ci  /* Gamma */
1440141cc406Sopenharmony_ci  if (dev->scan_mode == MATSUSHITA_GRAYSCALE)
1441141cc406Sopenharmony_ci    {
1442141cc406Sopenharmony_ci      i = get_string_list_index (gamma_list, dev->val[OPT_GAMMA].s);
1443141cc406Sopenharmony_ci      window[52] = gamma_val[i];
1444141cc406Sopenharmony_ci    }
1445141cc406Sopenharmony_ci
1446141cc406Sopenharmony_ci  /* Feeder mode */
1447141cc406Sopenharmony_ci  i = get_string_list_index (feeder_mode_list, dev->val[OPT_FEEDER_MODE].s);
1448141cc406Sopenharmony_ci  window[65] = feeder_mode_val[i];
1449141cc406Sopenharmony_ci
1450141cc406Sopenharmony_ci  /* Image emphasis */
1451141cc406Sopenharmony_ci  i = get_string_list_index (scanners[dev->scnum].image_emphasis_list,
1452141cc406Sopenharmony_ci			     dev->val[OPT_IMAGE_EMPHASIS].s);
1453141cc406Sopenharmony_ci  window[51] = scanners[dev->scnum].image_emphasis_val[i];
1454141cc406Sopenharmony_ci
1455141cc406Sopenharmony_ci  /* White level */
1456141cc406Sopenharmony_ci  i = get_string_list_index (white_level_list, dev->val[OPT_WHITE_LEVEL].s);
1457141cc406Sopenharmony_ci  window[68] = white_level_val[i];
1458141cc406Sopenharmony_ci
1459141cc406Sopenharmony_ci  if (dev->scan_mode == MATSUSHITA_BW ||
1460141cc406Sopenharmony_ci      dev->scan_mode == MATSUSHITA_HALFTONE)
1461141cc406Sopenharmony_ci    {
1462141cc406Sopenharmony_ci
1463141cc406Sopenharmony_ci      /* Noise reduction */
1464141cc406Sopenharmony_ci      i = get_string_list_index (noise_reduction_list,
1465141cc406Sopenharmony_ci				 dev->val[OPT_NOISE_REDUCTION].s);
1466141cc406Sopenharmony_ci      window[69] = noise_reduction_val[i];
1467141cc406Sopenharmony_ci
1468141cc406Sopenharmony_ci      /* Automatic separation */
1469141cc406Sopenharmony_ci      if (dev->val[OPT_AUTOMATIC_SEPARATION].w)
1470141cc406Sopenharmony_ci	{
1471141cc406Sopenharmony_ci	  window[67] = 0x80;
1472141cc406Sopenharmony_ci	}
1473141cc406Sopenharmony_ci
1474141cc406Sopenharmony_ci      /* Automatic threshold. Must be last because it may override
1475141cc406Sopenharmony_ci       * some previous options. */
1476141cc406Sopenharmony_ci      i = get_string_list_index (automatic_threshold_list,
1477141cc406Sopenharmony_ci				 dev->val[OPT_AUTOMATIC_THRESHOLD].s);
1478141cc406Sopenharmony_ci      window[66] = automatic_threshold_val[i];
1479141cc406Sopenharmony_ci
1480141cc406Sopenharmony_ci      if (automatic_threshold_val[i] != 0)
1481141cc406Sopenharmony_ci	{
1482141cc406Sopenharmony_ci	  /* Automatic threshold is enabled. */
1483141cc406Sopenharmony_ci	  window[30] = 0;	/* brightness. */
1484141cc406Sopenharmony_ci	  window[31] = 0;	/* same as brightness. */
1485141cc406Sopenharmony_ci	  window[32] = 0;	/* contrast */
1486141cc406Sopenharmony_ci	  window[33] = 0;	/* B&W mode */
1487141cc406Sopenharmony_ci	  window[36] = 0;	/* Halftone pattern. */
1488141cc406Sopenharmony_ci	  window[51] = 0;	/* Image emphasis */
1489141cc406Sopenharmony_ci	  window[67] = 0;	/* Automatic separation */
1490141cc406Sopenharmony_ci	  window[68] = 0;	/* White level */
1491141cc406Sopenharmony_ci	  window[69] = 0;	/* Noise reduction */
1492141cc406Sopenharmony_ci	}
1493141cc406Sopenharmony_ci    }
1494141cc406Sopenharmony_ci
1495141cc406Sopenharmony_ci  hexdump (DBG_info2, "windows", window, 72);
1496141cc406Sopenharmony_ci
1497141cc406Sopenharmony_ci  status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
1498141cc406Sopenharmony_ci							window, sizeof (window), NULL, NULL);
1499141cc406Sopenharmony_ci
1500141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_set_window: exit, status=%d\n", status);
1501141cc406Sopenharmony_ci
1502141cc406Sopenharmony_ci  return status;
1503141cc406Sopenharmony_ci}
1504141cc406Sopenharmony_ci
1505141cc406Sopenharmony_ci/* Read the image from the scanner and fill the temporary buffer with it. */
1506141cc406Sopenharmony_cistatic SANE_Status
1507141cc406Sopenharmony_cimatsushita_fill_image (Matsushita_Scanner * dev)
1508141cc406Sopenharmony_ci{
1509141cc406Sopenharmony_ci  SANE_Status status;
1510141cc406Sopenharmony_ci  size_t size;
1511141cc406Sopenharmony_ci  CDB cdb;
1512141cc406Sopenharmony_ci
1513141cc406Sopenharmony_ci  DBG (DBG_proc, "matsushita_fill_image: enter\n");
1514141cc406Sopenharmony_ci
1515141cc406Sopenharmony_ci  assert (dev->image_begin == dev->image_end);
1516141cc406Sopenharmony_ci  assert (dev->real_bytes_left > 0);
1517141cc406Sopenharmony_ci
1518141cc406Sopenharmony_ci  dev->image_begin = 0;
1519141cc406Sopenharmony_ci  dev->image_end = 0;
1520141cc406Sopenharmony_ci
1521141cc406Sopenharmony_ci  while (dev->real_bytes_left)
1522141cc406Sopenharmony_ci    {
1523141cc406Sopenharmony_ci
1524141cc406Sopenharmony_ci      /*
1525141cc406Sopenharmony_ci       * Try to read the maximum number of bytes.
1526141cc406Sopenharmony_ci       *
1527141cc406Sopenharmony_ci       * The windows driver reads no more than 0x8000 byte.
1528141cc406Sopenharmony_ci       *
1529141cc406Sopenharmony_ci       * This backend operates differently than the windows
1530141cc406Sopenharmony_ci       * driver. The windows TWAIN driver always read 2 more bytes
1531141cc406Sopenharmony_ci       * at the end, so it gets a CHECK CONDITION with a short read
1532141cc406Sopenharmony_ci       * sense. Since the linux scsi layer seem to be buggy
1533141cc406Sopenharmony_ci       * regarding the resid, always read exactly the number of
1534141cc406Sopenharmony_ci       * remaining bytes.
1535141cc406Sopenharmony_ci       */
1536141cc406Sopenharmony_ci
1537141cc406Sopenharmony_ci      size = dev->real_bytes_left;
1538141cc406Sopenharmony_ci      if (size > dev->image_size - dev->image_end)
1539141cc406Sopenharmony_ci	size = dev->image_size - dev->image_end;
1540141cc406Sopenharmony_ci      if (size > 0x8000)
1541141cc406Sopenharmony_ci	size = 0x8000;
1542141cc406Sopenharmony_ci
1543141cc406Sopenharmony_ci      if (size == 0)
1544141cc406Sopenharmony_ci	{
1545141cc406Sopenharmony_ci	  /* Probably reached the end of the buffer.
1546141cc406Sopenharmony_ci	   * Check, just in case. */
1547141cc406Sopenharmony_ci	  assert (dev->image_end != 0);
1548141cc406Sopenharmony_ci	  return (SANE_STATUS_GOOD);
1549141cc406Sopenharmony_ci	}
1550141cc406Sopenharmony_ci
1551141cc406Sopenharmony_ci      DBG (DBG_info, "sane_read: to read   = %ld bytes (bpl=%d)\n",
1552141cc406Sopenharmony_ci	   (long) size, dev->params.bytes_per_line);
1553141cc406Sopenharmony_ci
1554141cc406Sopenharmony_ci      MKSCSI_READ_10 (cdb, 0, 0, size);
1555141cc406Sopenharmony_ci      cdb.data[4] = dev->page_num;	/* May be cdb.data[3] too? */
1556141cc406Sopenharmony_ci      cdb.data[5] = dev->page_side;
1557141cc406Sopenharmony_ci
1558141cc406Sopenharmony_ci      hexdump (DBG_info2, "sane_read: READ_10 CDB", cdb.data, 10);
1559141cc406Sopenharmony_ci
1560141cc406Sopenharmony_ci      status = sanei_scsi_cmd2 (dev->sfd, cdb.data, cdb.len,
1561141cc406Sopenharmony_ci				NULL, 0, dev->buffer, &size);
1562141cc406Sopenharmony_ci
1563141cc406Sopenharmony_ci      if (status == SANE_STATUS_EOF)
1564141cc406Sopenharmony_ci	{
1565141cc406Sopenharmony_ci	  DBG (DBG_proc, "sane_read: exit, end of page scan\n");
1566141cc406Sopenharmony_ci	  return (SANE_STATUS_EOF);
1567141cc406Sopenharmony_ci	}
1568141cc406Sopenharmony_ci
1569141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1570141cc406Sopenharmony_ci	{
1571141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_read: cannot read from the scanner\n");
1572141cc406Sopenharmony_ci	  return status;
1573141cc406Sopenharmony_ci	}
1574141cc406Sopenharmony_ci
1575141cc406Sopenharmony_ci      dev->real_bytes_left -= size;
1576141cc406Sopenharmony_ci
1577141cc406Sopenharmony_ci      switch (dev->depth)
1578141cc406Sopenharmony_ci	{
1579141cc406Sopenharmony_ci	case 1:
1580141cc406Sopenharmony_ci	  {
1581141cc406Sopenharmony_ci	    /* For Black & White, the bits in every bytes are mirrored.
1582141cc406Sopenharmony_ci	     * for instance 11010001 is coded as 10001011 */
1583141cc406Sopenharmony_ci
1584141cc406Sopenharmony_ci	    unsigned char *src = dev->buffer;
1585141cc406Sopenharmony_ci	    unsigned char *dest = dev->image + dev->image_end;
1586141cc406Sopenharmony_ci	    unsigned char s;
1587141cc406Sopenharmony_ci	    unsigned char d;
1588141cc406Sopenharmony_ci
1589141cc406Sopenharmony_ci	    size_t i;
1590141cc406Sopenharmony_ci
1591141cc406Sopenharmony_ci	    for (i = 0; i < size; i++)
1592141cc406Sopenharmony_ci	      {
1593141cc406Sopenharmony_ci		s = *src;
1594141cc406Sopenharmony_ci		d = 0;
1595141cc406Sopenharmony_ci		if (s & 0x01)
1596141cc406Sopenharmony_ci		  d |= 0x80;
1597141cc406Sopenharmony_ci		if (s & 0x02)
1598141cc406Sopenharmony_ci		  d |= 0x40;
1599141cc406Sopenharmony_ci		if (s & 0x04)
1600141cc406Sopenharmony_ci		  d |= 0x20;
1601141cc406Sopenharmony_ci		if (s & 0x08)
1602141cc406Sopenharmony_ci		  d |= 0x10;
1603141cc406Sopenharmony_ci		if (s & 0x10)
1604141cc406Sopenharmony_ci		  d |= 0x08;
1605141cc406Sopenharmony_ci		if (s & 0x20)
1606141cc406Sopenharmony_ci		  d |= 0x04;
1607141cc406Sopenharmony_ci		if (s & 0x40)
1608141cc406Sopenharmony_ci		  d |= 0x02;
1609141cc406Sopenharmony_ci		if (s & 0x80)
1610141cc406Sopenharmony_ci		  d |= 0x01;
1611141cc406Sopenharmony_ci		*dest = d;
1612141cc406Sopenharmony_ci		src++;
1613141cc406Sopenharmony_ci		dest++;
1614141cc406Sopenharmony_ci	      }
1615141cc406Sopenharmony_ci	  }
1616141cc406Sopenharmony_ci	  break;
1617141cc406Sopenharmony_ci
1618141cc406Sopenharmony_ci	case 4:
1619141cc406Sopenharmony_ci	  {
1620141cc406Sopenharmony_ci	    /* Adjust from a depth of 4 bits ([0..15]) to
1621141cc406Sopenharmony_ci	     * a depth of 8 bits ([0..255]) */
1622141cc406Sopenharmony_ci
1623141cc406Sopenharmony_ci	    unsigned char *src = dev->buffer;
1624141cc406Sopenharmony_ci	    unsigned char *dest = dev->image + dev->image_end;
1625141cc406Sopenharmony_ci	    size_t i;
1626141cc406Sopenharmony_ci
1627141cc406Sopenharmony_ci	    /* n bytes from image --> 2*n bytes in buf. */
1628141cc406Sopenharmony_ci
1629141cc406Sopenharmony_ci	    for (i = 0; i < size; i++)
1630141cc406Sopenharmony_ci	      {
1631141cc406Sopenharmony_ci		*dest = ((*src & 0x0f) >> 0) * 17;
1632141cc406Sopenharmony_ci		dest++;
1633141cc406Sopenharmony_ci		*dest = ((*src & 0xf0) >> 4) * 17;
1634141cc406Sopenharmony_ci		dest++;
1635141cc406Sopenharmony_ci		src++;
1636141cc406Sopenharmony_ci	      }
1637141cc406Sopenharmony_ci
1638141cc406Sopenharmony_ci	    size *= 2;
1639141cc406Sopenharmony_ci	  }
1640141cc406Sopenharmony_ci	  break;
1641141cc406Sopenharmony_ci
1642141cc406Sopenharmony_ci	default:
1643141cc406Sopenharmony_ci	  memcpy (dev->image + dev->image_end, dev->buffer, size);
1644141cc406Sopenharmony_ci	  break;
1645141cc406Sopenharmony_ci	}
1646141cc406Sopenharmony_ci
1647141cc406Sopenharmony_ci      dev->image_end += size;
1648141cc406Sopenharmony_ci
1649141cc406Sopenharmony_ci    }
1650141cc406Sopenharmony_ci
1651141cc406Sopenharmony_ci  return (SANE_STATUS_GOOD);	/* unreachable */
1652141cc406Sopenharmony_ci}
1653141cc406Sopenharmony_ci
1654141cc406Sopenharmony_ci/* Copy from the raw buffer to the buffer given by the backend.
1655141cc406Sopenharmony_ci *
1656141cc406Sopenharmony_ci * len in input is the maximum length available in buf, and, in
1657141cc406Sopenharmony_ci * output, is the length written into buf.
1658141cc406Sopenharmony_ci */
1659141cc406Sopenharmony_cistatic void
1660141cc406Sopenharmony_cimatsushita_copy_raw_to_frontend (Matsushita_Scanner * dev, SANE_Byte * buf,
1661141cc406Sopenharmony_ci				 size_t * len)
1662141cc406Sopenharmony_ci{
1663141cc406Sopenharmony_ci  size_t size;
1664141cc406Sopenharmony_ci
1665141cc406Sopenharmony_ci  size = dev->image_end - dev->image_begin;
1666141cc406Sopenharmony_ci  if (size > *len)
1667141cc406Sopenharmony_ci    {
1668141cc406Sopenharmony_ci      size = *len;
1669141cc406Sopenharmony_ci    }
1670141cc406Sopenharmony_ci  *len = size;
1671141cc406Sopenharmony_ci
1672141cc406Sopenharmony_ci  memcpy (buf, dev->image + dev->image_begin, size);
1673141cc406Sopenharmony_ci  dev->image_begin += size;
1674141cc406Sopenharmony_ci}
1675141cc406Sopenharmony_ci
1676141cc406Sopenharmony_ci/* Stop a scan. */
1677141cc406Sopenharmony_cistatic SANE_Status
1678141cc406Sopenharmony_cido_cancel (Matsushita_Scanner * dev)
1679141cc406Sopenharmony_ci{
1680141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "do_cancel enter\n");
1681141cc406Sopenharmony_ci
1682141cc406Sopenharmony_ci  if (dev->scanning == SANE_TRUE)
1683141cc406Sopenharmony_ci    {
1684141cc406Sopenharmony_ci
1685141cc406Sopenharmony_ci      /* Reset the scanner */
1686141cc406Sopenharmony_ci      matsushita_reset_window (dev);
1687141cc406Sopenharmony_ci
1688141cc406Sopenharmony_ci      matsushita_close (dev);
1689141cc406Sopenharmony_ci    }
1690141cc406Sopenharmony_ci
1691141cc406Sopenharmony_ci  dev->scanning = SANE_FALSE;
1692141cc406Sopenharmony_ci
1693141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "do_cancel exit\n");
1694141cc406Sopenharmony_ci
1695141cc406Sopenharmony_ci  return SANE_STATUS_CANCELLED;
1696141cc406Sopenharmony_ci}
1697141cc406Sopenharmony_ci
1698141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/
1699141cc406Sopenharmony_ci
1700141cc406Sopenharmony_ci/* Entry points */
1701141cc406Sopenharmony_ci
1702141cc406Sopenharmony_ciSANE_Status
1703141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize)
1704141cc406Sopenharmony_ci{
1705141cc406Sopenharmony_ci  FILE *fp;
1706141cc406Sopenharmony_ci  char dev_name[PATH_MAX];
1707141cc406Sopenharmony_ci  size_t len;
1708141cc406Sopenharmony_ci
1709141cc406Sopenharmony_ci  DBG_INIT ();
1710141cc406Sopenharmony_ci
1711141cc406Sopenharmony_ci  DBG (DBG_sane_init, "sane_init\n");
1712141cc406Sopenharmony_ci
1713141cc406Sopenharmony_ci  DBG (DBG_error, "This is sane-matsushita version %d.%d-%d\n", SANE_CURRENT_MAJOR,
1714141cc406Sopenharmony_ci       SANE_CURRENT_MINOR, BUILD);
1715141cc406Sopenharmony_ci  DBG (DBG_error, "(C) 2002 by Frank Zago\n");
1716141cc406Sopenharmony_ci
1717141cc406Sopenharmony_ci  if (version_code)
1718141cc406Sopenharmony_ci    {
1719141cc406Sopenharmony_ci      *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
1720141cc406Sopenharmony_ci    }
1721141cc406Sopenharmony_ci
1722141cc406Sopenharmony_ci  fp = sanei_config_open (MATSUSHITA_CONFIG_FILE);
1723141cc406Sopenharmony_ci  if (!fp)
1724141cc406Sopenharmony_ci    {
1725141cc406Sopenharmony_ci      /* default to /dev/scanner instead of insisting on config file */
1726141cc406Sopenharmony_ci      attach_scanner ("/dev/scanner", 0);
1727141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1728141cc406Sopenharmony_ci    }
1729141cc406Sopenharmony_ci
1730141cc406Sopenharmony_ci  while (sanei_config_read (dev_name, sizeof (dev_name), fp))
1731141cc406Sopenharmony_ci    {
1732141cc406Sopenharmony_ci      if (dev_name[0] == '#')	/* ignore line comments */
1733141cc406Sopenharmony_ci	continue;
1734141cc406Sopenharmony_ci      len = strlen (dev_name);
1735141cc406Sopenharmony_ci
1736141cc406Sopenharmony_ci      if (!len)
1737141cc406Sopenharmony_ci	continue;		/* ignore empty lines */
1738141cc406Sopenharmony_ci
1739141cc406Sopenharmony_ci      sanei_config_attach_matching_devices (dev_name, attach_one);
1740141cc406Sopenharmony_ci    }
1741141cc406Sopenharmony_ci
1742141cc406Sopenharmony_ci  fclose (fp);
1743141cc406Sopenharmony_ci
1744141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_init: leave\n");
1745141cc406Sopenharmony_ci
1746141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1747141cc406Sopenharmony_ci}
1748141cc406Sopenharmony_ci
1749141cc406Sopenharmony_ciSANE_Status
1750141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool __sane_unused__ local_only)
1751141cc406Sopenharmony_ci{
1752141cc406Sopenharmony_ci  Matsushita_Scanner *dev;
1753141cc406Sopenharmony_ci  int i;
1754141cc406Sopenharmony_ci
1755141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_devices: enter\n");
1756141cc406Sopenharmony_ci
1757141cc406Sopenharmony_ci  if (devlist)
1758141cc406Sopenharmony_ci    free (devlist);
1759141cc406Sopenharmony_ci
1760141cc406Sopenharmony_ci  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
1761141cc406Sopenharmony_ci  if (!devlist)
1762141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1763141cc406Sopenharmony_ci
1764141cc406Sopenharmony_ci  i = 0;
1765141cc406Sopenharmony_ci  for (dev = first_dev; i < num_devices; dev = dev->next)
1766141cc406Sopenharmony_ci    devlist[i++] = &dev->sane;
1767141cc406Sopenharmony_ci  devlist[i++] = 0;
1768141cc406Sopenharmony_ci
1769141cc406Sopenharmony_ci  *device_list = devlist;
1770141cc406Sopenharmony_ci
1771141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_devices: exit\n");
1772141cc406Sopenharmony_ci
1773141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1774141cc406Sopenharmony_ci}
1775141cc406Sopenharmony_ci
1776141cc406Sopenharmony_ciSANE_Status
1777141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
1778141cc406Sopenharmony_ci{
1779141cc406Sopenharmony_ci  Matsushita_Scanner *dev;
1780141cc406Sopenharmony_ci  SANE_Status status;
1781141cc406Sopenharmony_ci
1782141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_open: enter\n");
1783141cc406Sopenharmony_ci
1784141cc406Sopenharmony_ci  /* search for devicename */
1785141cc406Sopenharmony_ci  if (devicename[0])
1786141cc406Sopenharmony_ci    {
1787141cc406Sopenharmony_ci      DBG (DBG_info, "sane_open: devicename=%s\n", devicename);
1788141cc406Sopenharmony_ci
1789141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
1790141cc406Sopenharmony_ci	{
1791141cc406Sopenharmony_ci	  if (strcmp (dev->sane.name, devicename) == 0)
1792141cc406Sopenharmony_ci	    {
1793141cc406Sopenharmony_ci	      break;
1794141cc406Sopenharmony_ci	    }
1795141cc406Sopenharmony_ci	}
1796141cc406Sopenharmony_ci
1797141cc406Sopenharmony_ci      if (!dev)
1798141cc406Sopenharmony_ci	{
1799141cc406Sopenharmony_ci	  status = attach_scanner (devicename, &dev);
1800141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
1801141cc406Sopenharmony_ci	    {
1802141cc406Sopenharmony_ci	      return status;
1803141cc406Sopenharmony_ci	    }
1804141cc406Sopenharmony_ci	}
1805141cc406Sopenharmony_ci    }
1806141cc406Sopenharmony_ci  else
1807141cc406Sopenharmony_ci    {
1808141cc406Sopenharmony_ci      DBG (DBG_sane_info, "sane_open: no devicename, opening first device\n");
1809141cc406Sopenharmony_ci      dev = first_dev;		/* empty devicename -> use first device */
1810141cc406Sopenharmony_ci    }
1811141cc406Sopenharmony_ci
1812141cc406Sopenharmony_ci  if (!dev)
1813141cc406Sopenharmony_ci    {
1814141cc406Sopenharmony_ci      DBG (DBG_error, "No scanner found\n");
1815141cc406Sopenharmony_ci
1816141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1817141cc406Sopenharmony_ci    }
1818141cc406Sopenharmony_ci
1819141cc406Sopenharmony_ci  /* Build a list a paper size that fit into this scanner. */
1820141cc406Sopenharmony_ci  matsushita_build_paper_sizes (dev);
1821141cc406Sopenharmony_ci
1822141cc406Sopenharmony_ci  matsushita_init_options (dev);
1823141cc406Sopenharmony_ci
1824141cc406Sopenharmony_ci  *handle = dev;
1825141cc406Sopenharmony_ci
1826141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_open: exit\n");
1827141cc406Sopenharmony_ci
1828141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1829141cc406Sopenharmony_ci}
1830141cc406Sopenharmony_ci
1831141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
1832141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
1833141cc406Sopenharmony_ci{
1834141cc406Sopenharmony_ci  Matsushita_Scanner *dev = handle;
1835141cc406Sopenharmony_ci
1836141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_option_descriptor: enter, option %d\n", option);
1837141cc406Sopenharmony_ci
1838141cc406Sopenharmony_ci  if ((unsigned) option >= OPT_NUM_OPTIONS)
1839141cc406Sopenharmony_ci    {
1840141cc406Sopenharmony_ci      return NULL;
1841141cc406Sopenharmony_ci    }
1842141cc406Sopenharmony_ci
1843141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_option_descriptor: exit\n");
1844141cc406Sopenharmony_ci
1845141cc406Sopenharmony_ci  return dev->opt + option;
1846141cc406Sopenharmony_ci}
1847141cc406Sopenharmony_ci
1848141cc406Sopenharmony_ciSANE_Status
1849141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
1850141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
1851141cc406Sopenharmony_ci{
1852141cc406Sopenharmony_ci  Matsushita_Scanner *dev = handle;
1853141cc406Sopenharmony_ci  SANE_Status status;
1854141cc406Sopenharmony_ci  SANE_Word cap;
1855141cc406Sopenharmony_ci  SANE_String_Const name;
1856141cc406Sopenharmony_ci  int i;
1857141cc406Sopenharmony_ci  SANE_Word value;
1858141cc406Sopenharmony_ci  int rc;
1859141cc406Sopenharmony_ci
1860141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_control_option: enter, option %d, action %d\n",
1861141cc406Sopenharmony_ci       option, action);
1862141cc406Sopenharmony_ci
1863141cc406Sopenharmony_ci  if (info)
1864141cc406Sopenharmony_ci    {
1865141cc406Sopenharmony_ci      *info = 0;
1866141cc406Sopenharmony_ci    }
1867141cc406Sopenharmony_ci
1868141cc406Sopenharmony_ci  if (dev->scanning)
1869141cc406Sopenharmony_ci    {
1870141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
1871141cc406Sopenharmony_ci    }
1872141cc406Sopenharmony_ci
1873141cc406Sopenharmony_ci  if (option < 0 || option >= OPT_NUM_OPTIONS)
1874141cc406Sopenharmony_ci    {
1875141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1876141cc406Sopenharmony_ci    }
1877141cc406Sopenharmony_ci
1878141cc406Sopenharmony_ci  cap = dev->opt[option].cap;
1879141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
1880141cc406Sopenharmony_ci    {
1881141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1882141cc406Sopenharmony_ci    }
1883141cc406Sopenharmony_ci
1884141cc406Sopenharmony_ci  name = dev->opt[option].name;
1885141cc406Sopenharmony_ci  if (!name)
1886141cc406Sopenharmony_ci    {
1887141cc406Sopenharmony_ci      name = "(no name)";
1888141cc406Sopenharmony_ci    }
1889141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
1890141cc406Sopenharmony_ci    {
1891141cc406Sopenharmony_ci
1892141cc406Sopenharmony_ci      switch (option)
1893141cc406Sopenharmony_ci	{
1894141cc406Sopenharmony_ci	  /* word options */
1895141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
1896141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1897141cc406Sopenharmony_ci	case OPT_TL_Y:
1898141cc406Sopenharmony_ci	case OPT_BR_Y:
1899141cc406Sopenharmony_ci	case OPT_TL_X:
1900141cc406Sopenharmony_ci	case OPT_BR_X:
1901141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
1902141cc406Sopenharmony_ci	case OPT_CONTRAST:
1903141cc406Sopenharmony_ci	case OPT_DUPLEX:
1904141cc406Sopenharmony_ci	case OPT_AUTOMATIC_SEPARATION:
1905141cc406Sopenharmony_ci	  *(SANE_Word *) val = dev->val[option].w;
1906141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1907141cc406Sopenharmony_ci
1908141cc406Sopenharmony_ci	  /* string options */
1909141cc406Sopenharmony_ci	case OPT_MODE:
1910141cc406Sopenharmony_ci	case OPT_FEEDER_MODE:
1911141cc406Sopenharmony_ci	case OPT_HALFTONE_PATTERN:
1912141cc406Sopenharmony_ci	case OPT_PAPER_SIZE:
1913141cc406Sopenharmony_ci	case OPT_AUTOMATIC_THRESHOLD:
1914141cc406Sopenharmony_ci	case OPT_WHITE_LEVEL:
1915141cc406Sopenharmony_ci	case OPT_NOISE_REDUCTION:
1916141cc406Sopenharmony_ci	case OPT_IMAGE_EMPHASIS:
1917141cc406Sopenharmony_ci	case OPT_GAMMA:
1918141cc406Sopenharmony_ci	  strcpy (val, dev->val[option].s);
1919141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1920141cc406Sopenharmony_ci
1921141cc406Sopenharmony_ci	default:
1922141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1923141cc406Sopenharmony_ci	}
1924141cc406Sopenharmony_ci    }
1925141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
1926141cc406Sopenharmony_ci    {
1927141cc406Sopenharmony_ci
1928141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
1929141cc406Sopenharmony_ci	{
1930141cc406Sopenharmony_ci	  DBG (DBG_error, "could not set option, not settable\n");
1931141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1932141cc406Sopenharmony_ci	}
1933141cc406Sopenharmony_ci
1934141cc406Sopenharmony_ci      status = sanei_constrain_value (dev->opt + option, val, info);
1935141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1936141cc406Sopenharmony_ci	{
1937141cc406Sopenharmony_ci	  DBG (DBG_error, "could not set option, invalid value\n");
1938141cc406Sopenharmony_ci	  return status;
1939141cc406Sopenharmony_ci	}
1940141cc406Sopenharmony_ci
1941141cc406Sopenharmony_ci      switch (option)
1942141cc406Sopenharmony_ci	{
1943141cc406Sopenharmony_ci
1944141cc406Sopenharmony_ci	  /* Side-effect options */
1945141cc406Sopenharmony_ci	case OPT_TL_Y:
1946141cc406Sopenharmony_ci	case OPT_BR_Y:
1947141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1948141cc406Sopenharmony_ci	  if (info)
1949141cc406Sopenharmony_ci	    {
1950141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_PARAMS;
1951141cc406Sopenharmony_ci	    }
1952141cc406Sopenharmony_ci	  dev->val[option].w = *(SANE_Word *) val;
1953141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1954141cc406Sopenharmony_ci
1955141cc406Sopenharmony_ci	  /* The length of X must be rounded (up). */
1956141cc406Sopenharmony_ci	case OPT_TL_X:
1957141cc406Sopenharmony_ci	case OPT_BR_X:
1958141cc406Sopenharmony_ci
1959141cc406Sopenharmony_ci	  value = mmToIlu (SANE_UNFIX (*(SANE_Word *) val));
1960141cc406Sopenharmony_ci
1961141cc406Sopenharmony_ci	  i = get_int_list_index (scanners[dev->scnum].resolutions_list,
1962141cc406Sopenharmony_ci				  dev->val[OPT_RESOLUTION].w);
1963141cc406Sopenharmony_ci
1964141cc406Sopenharmony_ci	  if (value & (scanners[dev->scnum].resolutions_round[i] - 1))
1965141cc406Sopenharmony_ci	    {
1966141cc406Sopenharmony_ci	      value =
1967141cc406Sopenharmony_ci		(value | (scanners[dev->scnum].resolutions_round[i] - 1)) + 1;
1968141cc406Sopenharmony_ci	      if (info)
1969141cc406Sopenharmony_ci		{
1970141cc406Sopenharmony_ci		  *info |= SANE_INFO_INEXACT;
1971141cc406Sopenharmony_ci		}
1972141cc406Sopenharmony_ci	    }
1973141cc406Sopenharmony_ci
1974141cc406Sopenharmony_ci	  *(SANE_Word *) val = SANE_FIX (iluToMm (value));
1975141cc406Sopenharmony_ci
1976141cc406Sopenharmony_ci	  dev->val[option].w = *(SANE_Word *) val;
1977141cc406Sopenharmony_ci
1978141cc406Sopenharmony_ci	  if (info)
1979141cc406Sopenharmony_ci	    {
1980141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_PARAMS;
1981141cc406Sopenharmony_ci	    }
1982141cc406Sopenharmony_ci
1983141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1984141cc406Sopenharmony_ci
1985141cc406Sopenharmony_ci	  /* Side-effect free options */
1986141cc406Sopenharmony_ci	case OPT_CONTRAST:
1987141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
1988141cc406Sopenharmony_ci	case OPT_DUPLEX:
1989141cc406Sopenharmony_ci	case OPT_AUTOMATIC_SEPARATION:
1990141cc406Sopenharmony_ci	  dev->val[option].w = *(SANE_Word *) val;
1991141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1992141cc406Sopenharmony_ci
1993141cc406Sopenharmony_ci	  /* String mode */
1994141cc406Sopenharmony_ci	case OPT_WHITE_LEVEL:
1995141cc406Sopenharmony_ci	case OPT_NOISE_REDUCTION:
1996141cc406Sopenharmony_ci	case OPT_IMAGE_EMPHASIS:
1997141cc406Sopenharmony_ci	case OPT_GAMMA:
1998141cc406Sopenharmony_ci	case OPT_FEEDER_MODE:
1999141cc406Sopenharmony_ci	  free (dev->val[option].s);
2000141cc406Sopenharmony_ci	  dev->val[option].s = (SANE_String) strdup (val);
2001141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
2002141cc406Sopenharmony_ci
2003141cc406Sopenharmony_ci	case OPT_MODE:
2004141cc406Sopenharmony_ci	  if (strcmp (dev->val[option].s, val) == 0)
2005141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
2006141cc406Sopenharmony_ci
2007141cc406Sopenharmony_ci	  free (dev->val[OPT_MODE].s);
2008141cc406Sopenharmony_ci	  dev->val[OPT_MODE].s = (SANE_Char *) strdup (val);
2009141cc406Sopenharmony_ci
2010141cc406Sopenharmony_ci	  /* Set default options for the scan modes. */
2011141cc406Sopenharmony_ci	  dev->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
2012141cc406Sopenharmony_ci	  dev->opt[OPT_AUTOMATIC_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2013141cc406Sopenharmony_ci	  dev->opt[OPT_AUTOMATIC_SEPARATION].cap |= SANE_CAP_INACTIVE;
2014141cc406Sopenharmony_ci	  dev->opt[OPT_NOISE_REDUCTION].cap |= SANE_CAP_INACTIVE;
2015141cc406Sopenharmony_ci	  dev->opt[OPT_GAMMA].cap |= SANE_CAP_INACTIVE;
2016141cc406Sopenharmony_ci
2017141cc406Sopenharmony_ci	  if (strcmp (dev->val[OPT_MODE].s, BLACK_WHITE_STR) == 0)
2018141cc406Sopenharmony_ci	    {
2019141cc406Sopenharmony_ci	      dev->depth = 1;
2020141cc406Sopenharmony_ci
2021141cc406Sopenharmony_ci	      dev->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE;
2022141cc406Sopenharmony_ci	      dev->opt[OPT_AUTOMATIC_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
2023141cc406Sopenharmony_ci	      dev->opt[OPT_AUTOMATIC_SEPARATION].cap &= ~SANE_CAP_INACTIVE;
2024141cc406Sopenharmony_ci	      dev->opt[OPT_NOISE_REDUCTION].cap &= ~SANE_CAP_INACTIVE;
2025141cc406Sopenharmony_ci
2026141cc406Sopenharmony_ci	      i = get_string_list_index (halftone_pattern_list,
2027141cc406Sopenharmony_ci					 dev->val[OPT_HALFTONE_PATTERN].s);
2028141cc406Sopenharmony_ci	      if (halftone_pattern_val[i] == -1)
2029141cc406Sopenharmony_ci		{
2030141cc406Sopenharmony_ci		  dev->scan_mode = MATSUSHITA_BW;
2031141cc406Sopenharmony_ci		}
2032141cc406Sopenharmony_ci	      else
2033141cc406Sopenharmony_ci		{
2034141cc406Sopenharmony_ci		  dev->scan_mode = MATSUSHITA_HALFTONE;
2035141cc406Sopenharmony_ci		}
2036141cc406Sopenharmony_ci	    }
2037141cc406Sopenharmony_ci	  else if (strcmp (dev->val[OPT_MODE].s, GRAY4_STR) == 0)
2038141cc406Sopenharmony_ci	    {
2039141cc406Sopenharmony_ci	      dev->scan_mode = MATSUSHITA_GRAYSCALE;
2040141cc406Sopenharmony_ci	      dev->depth = 4;
2041141cc406Sopenharmony_ci
2042141cc406Sopenharmony_ci	      dev->opt[OPT_GAMMA].cap &= ~SANE_CAP_INACTIVE;
2043141cc406Sopenharmony_ci	    }
2044141cc406Sopenharmony_ci	  else if (strcmp (dev->val[OPT_MODE].s, GRAY8_STR) == 0)
2045141cc406Sopenharmony_ci	    {
2046141cc406Sopenharmony_ci	      dev->scan_mode = MATSUSHITA_GRAYSCALE;
2047141cc406Sopenharmony_ci	      dev->depth = 8;
2048141cc406Sopenharmony_ci
2049141cc406Sopenharmony_ci	      dev->opt[OPT_GAMMA].cap &= ~SANE_CAP_INACTIVE;
2050141cc406Sopenharmony_ci	    }
2051141cc406Sopenharmony_ci	  else
2052141cc406Sopenharmony_ci	    {
2053141cc406Sopenharmony_ci	      assert (0 == 1);
2054141cc406Sopenharmony_ci	    }
2055141cc406Sopenharmony_ci
2056141cc406Sopenharmony_ci	  /* Some options might not be supported by the scanner. */
2057141cc406Sopenharmony_ci	  if ((scanners[dev->scnum].cap & MAT_CAP_GAMMA) == 0)
2058141cc406Sopenharmony_ci	    dev->opt[OPT_GAMMA].cap |= SANE_CAP_INACTIVE;
2059141cc406Sopenharmony_ci
2060141cc406Sopenharmony_ci	  if (info)
2061141cc406Sopenharmony_ci	    {
2062141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
2063141cc406Sopenharmony_ci	    }
2064141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
2065141cc406Sopenharmony_ci
2066141cc406Sopenharmony_ci	case OPT_HALFTONE_PATTERN:
2067141cc406Sopenharmony_ci	  free (dev->val[option].s);
2068141cc406Sopenharmony_ci	  dev->val[option].s = (SANE_String) strdup (val);
2069141cc406Sopenharmony_ci	  i = get_string_list_index (halftone_pattern_list,
2070141cc406Sopenharmony_ci				     dev->val[OPT_HALFTONE_PATTERN].s);
2071141cc406Sopenharmony_ci	  if (halftone_pattern_val[i] == -1)
2072141cc406Sopenharmony_ci	    {
2073141cc406Sopenharmony_ci	      dev->scan_mode = MATSUSHITA_BW;
2074141cc406Sopenharmony_ci	    }
2075141cc406Sopenharmony_ci	  else
2076141cc406Sopenharmony_ci	    {
2077141cc406Sopenharmony_ci	      dev->scan_mode = MATSUSHITA_HALFTONE;
2078141cc406Sopenharmony_ci	    }
2079141cc406Sopenharmony_ci
2080141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
2081141cc406Sopenharmony_ci
2082141cc406Sopenharmony_ci	case OPT_PAPER_SIZE:
2083141cc406Sopenharmony_ci	  if (strcmp (dev->val[option].s, val) == 0)
2084141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
2085141cc406Sopenharmony_ci
2086141cc406Sopenharmony_ci	  free (dev->val[OPT_PAPER_SIZE].s);
2087141cc406Sopenharmony_ci	  dev->val[OPT_PAPER_SIZE].s = (SANE_Char *) strdup (val);
2088141cc406Sopenharmony_ci
2089141cc406Sopenharmony_ci	  i = get_string_list_index (dev->paper_sizes_list,
2090141cc406Sopenharmony_ci				     dev->val[OPT_PAPER_SIZE].s);
2091141cc406Sopenharmony_ci	  i = dev->paper_sizes_val[i];
2092141cc406Sopenharmony_ci
2093141cc406Sopenharmony_ci	  /* Set the 4 corners values. */
2094141cc406Sopenharmony_ci	  value = 0;
2095141cc406Sopenharmony_ci	  rc = sane_control_option (handle, OPT_TL_X, SANE_ACTION_SET_VALUE,
2096141cc406Sopenharmony_ci				    &value, info);
2097141cc406Sopenharmony_ci	  assert (rc == SANE_STATUS_GOOD);
2098141cc406Sopenharmony_ci
2099141cc406Sopenharmony_ci	  value = 0;
2100141cc406Sopenharmony_ci	  rc = sane_control_option (handle, OPT_TL_Y, SANE_ACTION_SET_VALUE,
2101141cc406Sopenharmony_ci				    &value, info);
2102141cc406Sopenharmony_ci	  assert (rc == SANE_STATUS_GOOD);
2103141cc406Sopenharmony_ci
2104141cc406Sopenharmony_ci	  value = SANE_FIX (paper_sizes[i].width);
2105141cc406Sopenharmony_ci	  rc = sane_control_option (handle, OPT_BR_X, SANE_ACTION_SET_VALUE,
2106141cc406Sopenharmony_ci				    &value, info);
2107141cc406Sopenharmony_ci	  assert (rc == SANE_STATUS_GOOD);
2108141cc406Sopenharmony_ci
2109141cc406Sopenharmony_ci	  value = SANE_FIX (paper_sizes[i].length);
2110141cc406Sopenharmony_ci	  rc = sane_control_option (handle, OPT_BR_Y, SANE_ACTION_SET_VALUE,
2111141cc406Sopenharmony_ci				    &value, info);
2112141cc406Sopenharmony_ci	  assert (rc == SANE_STATUS_GOOD);
2113141cc406Sopenharmony_ci
2114141cc406Sopenharmony_ci	  if (info)
2115141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS;
2116141cc406Sopenharmony_ci
2117141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
2118141cc406Sopenharmony_ci
2119141cc406Sopenharmony_ci	case OPT_AUTOMATIC_THRESHOLD:
2120141cc406Sopenharmony_ci	  if (strcmp (dev->val[option].s, val) == 0)
2121141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
2122141cc406Sopenharmony_ci
2123141cc406Sopenharmony_ci	  free (dev->val[option].s);
2124141cc406Sopenharmony_ci	  dev->val[option].s = (SANE_Char *) strdup (val);
2125141cc406Sopenharmony_ci
2126141cc406Sopenharmony_ci	  /* If the threshold is not set to none, some option must
2127141cc406Sopenharmony_ci	   * disappear. */
2128141cc406Sopenharmony_ci	  dev->opt[OPT_WHITE_LEVEL].cap |= SANE_CAP_INACTIVE;
2129141cc406Sopenharmony_ci	  dev->opt[OPT_NOISE_REDUCTION].cap |= SANE_CAP_INACTIVE;
2130141cc406Sopenharmony_ci	  dev->opt[OPT_IMAGE_EMPHASIS].cap |= SANE_CAP_INACTIVE;
2131141cc406Sopenharmony_ci	  dev->opt[OPT_AUTOMATIC_SEPARATION].cap |= SANE_CAP_INACTIVE;
2132141cc406Sopenharmony_ci	  dev->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
2133141cc406Sopenharmony_ci
2134141cc406Sopenharmony_ci	  if (strcmp (dev->val[option].s, automatic_threshold_list[0]) == 0)
2135141cc406Sopenharmony_ci	    {
2136141cc406Sopenharmony_ci	      dev->opt[OPT_WHITE_LEVEL].cap &= ~SANE_CAP_INACTIVE;
2137141cc406Sopenharmony_ci	      dev->opt[OPT_NOISE_REDUCTION].cap &= ~SANE_CAP_INACTIVE;
2138141cc406Sopenharmony_ci	      dev->opt[OPT_IMAGE_EMPHASIS].cap &= ~SANE_CAP_INACTIVE;
2139141cc406Sopenharmony_ci	      dev->opt[OPT_AUTOMATIC_SEPARATION].cap &= ~SANE_CAP_INACTIVE;
2140141cc406Sopenharmony_ci	      if (dev->scan_mode == MATSUSHITA_BW
2141141cc406Sopenharmony_ci		  || dev->scan_mode == MATSUSHITA_HALFTONE)
2142141cc406Sopenharmony_ci		{
2143141cc406Sopenharmony_ci		  dev->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE;
2144141cc406Sopenharmony_ci		}
2145141cc406Sopenharmony_ci	    }
2146141cc406Sopenharmony_ci
2147141cc406Sopenharmony_ci	  if (info)
2148141cc406Sopenharmony_ci	    {
2149141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
2150141cc406Sopenharmony_ci	    }
2151141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
2152141cc406Sopenharmony_ci
2153141cc406Sopenharmony_ci	default:
2154141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
2155141cc406Sopenharmony_ci	}
2156141cc406Sopenharmony_ci    }
2157141cc406Sopenharmony_ci
2158141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_control_option: exit, bad\n");
2159141cc406Sopenharmony_ci
2160141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
2161141cc406Sopenharmony_ci}
2162141cc406Sopenharmony_ci
2163141cc406Sopenharmony_ciSANE_Status
2164141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
2165141cc406Sopenharmony_ci{
2166141cc406Sopenharmony_ci  Matsushita_Scanner *dev = handle;
2167141cc406Sopenharmony_ci
2168141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_parameters: enter\n");
2169141cc406Sopenharmony_ci
2170141cc406Sopenharmony_ci  if (!(dev->scanning))
2171141cc406Sopenharmony_ci    {
2172141cc406Sopenharmony_ci
2173141cc406Sopenharmony_ci      /* Setup the parameters for the scan. These values will be re-used
2174141cc406Sopenharmony_ci       * in the SET WINDOWS command. */
2175141cc406Sopenharmony_ci      dev->resolution = dev->val[OPT_RESOLUTION].w;
2176141cc406Sopenharmony_ci
2177141cc406Sopenharmony_ci      dev->x_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_X].w));
2178141cc406Sopenharmony_ci      dev->y_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_Y].w));
2179141cc406Sopenharmony_ci      dev->x_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_X].w));
2180141cc406Sopenharmony_ci      dev->y_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_Y].w));
2181141cc406Sopenharmony_ci
2182141cc406Sopenharmony_ci      /* Check the corners are OK. */
2183141cc406Sopenharmony_ci      if (dev->x_tl > dev->x_br)
2184141cc406Sopenharmony_ci	{
2185141cc406Sopenharmony_ci	  int s;
2186141cc406Sopenharmony_ci	  s = dev->x_tl;
2187141cc406Sopenharmony_ci	  dev->x_tl = dev->x_br;
2188141cc406Sopenharmony_ci	  dev->x_br = s;
2189141cc406Sopenharmony_ci	}
2190141cc406Sopenharmony_ci      if (dev->y_tl > dev->y_br)
2191141cc406Sopenharmony_ci	{
2192141cc406Sopenharmony_ci	  int s;
2193141cc406Sopenharmony_ci	  s = dev->y_tl;
2194141cc406Sopenharmony_ci	  dev->y_tl = dev->y_br;
2195141cc406Sopenharmony_ci	  dev->y_br = s;
2196141cc406Sopenharmony_ci	}
2197141cc406Sopenharmony_ci
2198141cc406Sopenharmony_ci      dev->width = dev->x_br - dev->x_tl;
2199141cc406Sopenharmony_ci      dev->length = dev->y_br - dev->y_tl;
2200141cc406Sopenharmony_ci
2201141cc406Sopenharmony_ci      /* Prepare the parameters for the caller. */
2202141cc406Sopenharmony_ci      memset (&dev->params, 0, sizeof (SANE_Parameters));
2203141cc406Sopenharmony_ci
2204141cc406Sopenharmony_ci      dev->params.format = SANE_FRAME_GRAY;
2205141cc406Sopenharmony_ci      dev->params.last_frame = SANE_TRUE;
2206141cc406Sopenharmony_ci      dev->params.pixels_per_line =
2207141cc406Sopenharmony_ci	(((dev->width * dev->resolution) / 1200) + 7) & ~0x7;
2208141cc406Sopenharmony_ci
2209141cc406Sopenharmony_ci      if (dev->depth == 4)
2210141cc406Sopenharmony_ci	{
2211141cc406Sopenharmony_ci	  dev->params.depth = 8;
2212141cc406Sopenharmony_ci	}
2213141cc406Sopenharmony_ci      else
2214141cc406Sopenharmony_ci	{
2215141cc406Sopenharmony_ci	  dev->params.depth = dev->depth;
2216141cc406Sopenharmony_ci	}
2217141cc406Sopenharmony_ci      dev->params.bytes_per_line =
2218141cc406Sopenharmony_ci	(dev->params.pixels_per_line / 8) * dev->params.depth;
2219141cc406Sopenharmony_ci      dev->params.lines = (dev->length * dev->resolution) / 1200;
2220141cc406Sopenharmony_ci    }
2221141cc406Sopenharmony_ci
2222141cc406Sopenharmony_ci  /* Return the current values. */
2223141cc406Sopenharmony_ci  if (params)
2224141cc406Sopenharmony_ci    {
2225141cc406Sopenharmony_ci      *params = (dev->params);
2226141cc406Sopenharmony_ci    }
2227141cc406Sopenharmony_ci
2228141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_parameters: exit\n");
2229141cc406Sopenharmony_ci
2230141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2231141cc406Sopenharmony_ci}
2232141cc406Sopenharmony_ci
2233141cc406Sopenharmony_ciSANE_Status
2234141cc406Sopenharmony_cisane_start (SANE_Handle handle)
2235141cc406Sopenharmony_ci{
2236141cc406Sopenharmony_ci  Matsushita_Scanner *dev = handle;
2237141cc406Sopenharmony_ci  SANE_Status status;
2238141cc406Sopenharmony_ci
2239141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: enter\n");
2240141cc406Sopenharmony_ci
2241141cc406Sopenharmony_ci  if (!(dev->scanning))
2242141cc406Sopenharmony_ci    {
2243141cc406Sopenharmony_ci
2244141cc406Sopenharmony_ci      sane_get_parameters (dev, NULL);
2245141cc406Sopenharmony_ci
2246141cc406Sopenharmony_ci      if (dev->image == NULL)
2247141cc406Sopenharmony_ci	{
2248141cc406Sopenharmony_ci	  dev->image_size = 3 * dev->buffer_size;
2249141cc406Sopenharmony_ci	  dev->image = malloc (dev->image_size);
2250141cc406Sopenharmony_ci	  if (dev->image == NULL)
2251141cc406Sopenharmony_ci	    {
2252141cc406Sopenharmony_ci	      return SANE_STATUS_NO_MEM;
2253141cc406Sopenharmony_ci	    }
2254141cc406Sopenharmony_ci	}
2255141cc406Sopenharmony_ci
2256141cc406Sopenharmony_ci      /* Open again the scanner. */
2257141cc406Sopenharmony_ci      if (sanei_scsi_open
2258141cc406Sopenharmony_ci	  (dev->devicename, &(dev->sfd), matsushita_sense_handler, dev) != 0)
2259141cc406Sopenharmony_ci	{
2260141cc406Sopenharmony_ci	  DBG (DBG_error, "ERROR: sane_start: open failed\n");
2261141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
2262141cc406Sopenharmony_ci	}
2263141cc406Sopenharmony_ci
2264141cc406Sopenharmony_ci      dev->page_side = 0;	/* page front */
2265141cc406Sopenharmony_ci      dev->page_num = 0;	/* first page */
2266141cc406Sopenharmony_ci
2267141cc406Sopenharmony_ci      /* The scanner must be ready. */
2268141cc406Sopenharmony_ci      status = matsushita_wait_scanner (dev);
2269141cc406Sopenharmony_ci      if (status)
2270141cc406Sopenharmony_ci	{
2271141cc406Sopenharmony_ci	  matsushita_close (dev);
2272141cc406Sopenharmony_ci	  return status;
2273141cc406Sopenharmony_ci	}
2274141cc406Sopenharmony_ci
2275141cc406Sopenharmony_ci      status = matsushita_reset_window (dev);
2276141cc406Sopenharmony_ci      if (status)
2277141cc406Sopenharmony_ci	{
2278141cc406Sopenharmony_ci	  matsushita_close (dev);
2279141cc406Sopenharmony_ci	  return status;
2280141cc406Sopenharmony_ci	}
2281141cc406Sopenharmony_ci
2282141cc406Sopenharmony_ci      status = matsushita_set_window (dev, PAGE_FRONT);
2283141cc406Sopenharmony_ci      if (status)
2284141cc406Sopenharmony_ci	{
2285141cc406Sopenharmony_ci	  matsushita_close (dev);
2286141cc406Sopenharmony_ci	  return status;
2287141cc406Sopenharmony_ci	}
2288141cc406Sopenharmony_ci
2289141cc406Sopenharmony_ci      if (dev->val[OPT_DUPLEX].w == SANE_TRUE)
2290141cc406Sopenharmony_ci	{
2291141cc406Sopenharmony_ci	  status = matsushita_set_window (dev, PAGE_BACK);
2292141cc406Sopenharmony_ci	  if (status)
2293141cc406Sopenharmony_ci	    {
2294141cc406Sopenharmony_ci	      matsushita_close (dev);
2295141cc406Sopenharmony_ci	      return status;
2296141cc406Sopenharmony_ci	    }
2297141cc406Sopenharmony_ci	}
2298141cc406Sopenharmony_ci
2299141cc406Sopenharmony_ci      status = matsushita_read_document_size (dev);
2300141cc406Sopenharmony_ci      if (status)
2301141cc406Sopenharmony_ci	{
2302141cc406Sopenharmony_ci	  matsushita_close (dev);
2303141cc406Sopenharmony_ci	  return status;
2304141cc406Sopenharmony_ci	}
2305141cc406Sopenharmony_ci
2306141cc406Sopenharmony_ci    }
2307141cc406Sopenharmony_ci  else
2308141cc406Sopenharmony_ci    {
2309141cc406Sopenharmony_ci      if (dev->val[OPT_DUPLEX].w == SANE_TRUE && dev->page_side == PAGE_FRONT)
2310141cc406Sopenharmony_ci	{
2311141cc406Sopenharmony_ci	  dev->page_side = PAGE_BACK;
2312141cc406Sopenharmony_ci	}
2313141cc406Sopenharmony_ci      else
2314141cc406Sopenharmony_ci	{
2315141cc406Sopenharmony_ci	  /* new sheet. */
2316141cc406Sopenharmony_ci	  dev->page_side = PAGE_FRONT;
2317141cc406Sopenharmony_ci	  dev->page_num++;
2318141cc406Sopenharmony_ci	}
2319141cc406Sopenharmony_ci
2320141cc406Sopenharmony_ci      status = matsushita_check_next_page (dev);
2321141cc406Sopenharmony_ci      if (status)
2322141cc406Sopenharmony_ci	{
2323141cc406Sopenharmony_ci	  return status;
2324141cc406Sopenharmony_ci	}
2325141cc406Sopenharmony_ci    }
2326141cc406Sopenharmony_ci
2327141cc406Sopenharmony_ci  dev->bytes_left = dev->params.bytes_per_line * dev->params.lines;
2328141cc406Sopenharmony_ci  dev->real_bytes_left = dev->params.bytes_per_line * dev->params.lines;
2329141cc406Sopenharmony_ci  if (dev->depth == 4)
2330141cc406Sopenharmony_ci    {
2331141cc406Sopenharmony_ci      /* Every byte read will be expanded into 2 bytes. */
2332141cc406Sopenharmony_ci      dev->real_bytes_left /= 2;
2333141cc406Sopenharmony_ci    }
2334141cc406Sopenharmony_ci
2335141cc406Sopenharmony_ci  dev->image_end = 0;
2336141cc406Sopenharmony_ci  dev->image_begin = 0;
2337141cc406Sopenharmony_ci
2338141cc406Sopenharmony_ci  dev->scanning = SANE_TRUE;
2339141cc406Sopenharmony_ci
2340141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: exit\n");
2341141cc406Sopenharmony_ci
2342141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2343141cc406Sopenharmony_ci}
2344141cc406Sopenharmony_ci
2345141cc406Sopenharmony_ciSANE_Status
2346141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
2347141cc406Sopenharmony_ci	   SANE_Int * len)
2348141cc406Sopenharmony_ci{
2349141cc406Sopenharmony_ci  SANE_Status status;
2350141cc406Sopenharmony_ci  Matsushita_Scanner *dev = handle;
2351141cc406Sopenharmony_ci  size_t size;
2352141cc406Sopenharmony_ci  int buf_offset;		/* offset into buf */
2353141cc406Sopenharmony_ci
2354141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_read: enter\n");
2355141cc406Sopenharmony_ci
2356141cc406Sopenharmony_ci  *len = 0;
2357141cc406Sopenharmony_ci
2358141cc406Sopenharmony_ci  if (!(dev->scanning))
2359141cc406Sopenharmony_ci    {
2360141cc406Sopenharmony_ci      /* OOPS, not scanning */
2361141cc406Sopenharmony_ci      return do_cancel (dev);
2362141cc406Sopenharmony_ci    }
2363141cc406Sopenharmony_ci
2364141cc406Sopenharmony_ci  if (dev->bytes_left <= 0)
2365141cc406Sopenharmony_ci    {
2366141cc406Sopenharmony_ci      return (SANE_STATUS_EOF);
2367141cc406Sopenharmony_ci    }
2368141cc406Sopenharmony_ci
2369141cc406Sopenharmony_ci  buf_offset = 0;
2370141cc406Sopenharmony_ci
2371141cc406Sopenharmony_ci  do
2372141cc406Sopenharmony_ci    {
2373141cc406Sopenharmony_ci      if (dev->image_begin == dev->image_end)
2374141cc406Sopenharmony_ci	{
2375141cc406Sopenharmony_ci	  /* Fill image */
2376141cc406Sopenharmony_ci	  status = matsushita_fill_image (dev);
2377141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
2378141cc406Sopenharmony_ci	    {
2379141cc406Sopenharmony_ci	      return (status);
2380141cc406Sopenharmony_ci	    }
2381141cc406Sopenharmony_ci	}
2382141cc406Sopenharmony_ci
2383141cc406Sopenharmony_ci      /* Something must have been read */
2384141cc406Sopenharmony_ci      if (dev->image_begin == dev->image_end)
2385141cc406Sopenharmony_ci	{
2386141cc406Sopenharmony_ci	  DBG (DBG_info, "sane_read: nothing read\n");
2387141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
2388141cc406Sopenharmony_ci	}
2389141cc406Sopenharmony_ci
2390141cc406Sopenharmony_ci      /* Copy the data to the frontend buffer. */
2391141cc406Sopenharmony_ci      size = max_len - buf_offset;
2392141cc406Sopenharmony_ci      if (size > dev->bytes_left)
2393141cc406Sopenharmony_ci	{
2394141cc406Sopenharmony_ci	  size = dev->bytes_left;
2395141cc406Sopenharmony_ci	}
2396141cc406Sopenharmony_ci      matsushita_copy_raw_to_frontend (dev, buf + buf_offset, &size);
2397141cc406Sopenharmony_ci
2398141cc406Sopenharmony_ci      buf_offset += size;
2399141cc406Sopenharmony_ci
2400141cc406Sopenharmony_ci      dev->bytes_left -= size;
2401141cc406Sopenharmony_ci      *len += size;
2402141cc406Sopenharmony_ci
2403141cc406Sopenharmony_ci    }
2404141cc406Sopenharmony_ci  while ((buf_offset != max_len) && dev->bytes_left);
2405141cc406Sopenharmony_ci
2406141cc406Sopenharmony_ci  DBG (DBG_info, "sane_read: leave, bytes_left=%ld\n", (long)dev->bytes_left);
2407141cc406Sopenharmony_ci
2408141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2409141cc406Sopenharmony_ci}
2410141cc406Sopenharmony_ci
2411141cc406Sopenharmony_ciSANE_Status
2412141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle __sane_unused__ handle, SANE_Bool __sane_unused__ non_blocking)
2413141cc406Sopenharmony_ci{
2414141cc406Sopenharmony_ci	SANE_Status status;
2415141cc406Sopenharmony_ci	Matsushita_Scanner *dev = handle;
2416141cc406Sopenharmony_ci
2417141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_set_io_mode: enter\n");
2418141cc406Sopenharmony_ci
2419141cc406Sopenharmony_ci    if (dev->scanning == SANE_FALSE)
2420141cc406Sopenharmony_ci    {
2421141cc406Sopenharmony_ci      return (SANE_STATUS_INVAL);
2422141cc406Sopenharmony_ci    }
2423141cc406Sopenharmony_ci
2424141cc406Sopenharmony_ci	if (non_blocking == SANE_FALSE) {
2425141cc406Sopenharmony_ci		status = SANE_STATUS_GOOD;
2426141cc406Sopenharmony_ci	} else {
2427141cc406Sopenharmony_ci		status = SANE_STATUS_UNSUPPORTED;
2428141cc406Sopenharmony_ci	}
2429141cc406Sopenharmony_ci
2430141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_set_io_mode: exit\n");
2431141cc406Sopenharmony_ci
2432141cc406Sopenharmony_ci  return status;
2433141cc406Sopenharmony_ci}
2434141cc406Sopenharmony_ci
2435141cc406Sopenharmony_ciSANE_Status
2436141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle __sane_unused__ handle, SANE_Int __sane_unused__ * fd)
2437141cc406Sopenharmony_ci{
2438141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_select_fd: enter\n");
2439141cc406Sopenharmony_ci
2440141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_select_fd: exit\n");
2441141cc406Sopenharmony_ci
2442141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
2443141cc406Sopenharmony_ci}
2444141cc406Sopenharmony_ci
2445141cc406Sopenharmony_civoid
2446141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
2447141cc406Sopenharmony_ci{
2448141cc406Sopenharmony_ci  Matsushita_Scanner *dev = handle;
2449141cc406Sopenharmony_ci
2450141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_cancel: enter\n");
2451141cc406Sopenharmony_ci
2452141cc406Sopenharmony_ci  do_cancel (dev);
2453141cc406Sopenharmony_ci
2454141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_cancel: exit\n");
2455141cc406Sopenharmony_ci}
2456141cc406Sopenharmony_ci
2457141cc406Sopenharmony_civoid
2458141cc406Sopenharmony_cisane_close (SANE_Handle handle)
2459141cc406Sopenharmony_ci{
2460141cc406Sopenharmony_ci  Matsushita_Scanner *dev = handle;
2461141cc406Sopenharmony_ci  Matsushita_Scanner *dev_tmp;
2462141cc406Sopenharmony_ci
2463141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_close: enter\n");
2464141cc406Sopenharmony_ci
2465141cc406Sopenharmony_ci  do_cancel (dev);
2466141cc406Sopenharmony_ci  matsushita_close (dev);
2467141cc406Sopenharmony_ci
2468141cc406Sopenharmony_ci  /* Unlink dev. */
2469141cc406Sopenharmony_ci  if (first_dev == dev)
2470141cc406Sopenharmony_ci    {
2471141cc406Sopenharmony_ci      first_dev = dev->next;
2472141cc406Sopenharmony_ci    }
2473141cc406Sopenharmony_ci  else
2474141cc406Sopenharmony_ci    {
2475141cc406Sopenharmony_ci      dev_tmp = first_dev;
2476141cc406Sopenharmony_ci      while (dev_tmp->next && dev_tmp->next != dev)
2477141cc406Sopenharmony_ci	{
2478141cc406Sopenharmony_ci	  dev_tmp = dev_tmp->next;
2479141cc406Sopenharmony_ci	}
2480141cc406Sopenharmony_ci      if (dev_tmp->next != NULL)
2481141cc406Sopenharmony_ci	{
2482141cc406Sopenharmony_ci	  dev_tmp->next = dev_tmp->next->next;
2483141cc406Sopenharmony_ci	}
2484141cc406Sopenharmony_ci    }
2485141cc406Sopenharmony_ci
2486141cc406Sopenharmony_ci  matsushita_free (dev);
2487141cc406Sopenharmony_ci  num_devices--;
2488141cc406Sopenharmony_ci
2489141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_close: exit\n");
2490141cc406Sopenharmony_ci}
2491141cc406Sopenharmony_ci
2492141cc406Sopenharmony_civoid
2493141cc406Sopenharmony_cisane_exit (void)
2494141cc406Sopenharmony_ci{
2495141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_exit: enter\n");
2496141cc406Sopenharmony_ci
2497141cc406Sopenharmony_ci  while (first_dev)
2498141cc406Sopenharmony_ci    {
2499141cc406Sopenharmony_ci      sane_close (first_dev);
2500141cc406Sopenharmony_ci    }
2501141cc406Sopenharmony_ci
2502141cc406Sopenharmony_ci  if (devlist)
2503141cc406Sopenharmony_ci    {
2504141cc406Sopenharmony_ci      free (devlist);
2505141cc406Sopenharmony_ci      devlist = NULL;
2506141cc406Sopenharmony_ci    }
2507141cc406Sopenharmony_ci
2508141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_exit: exit\n");
2509141cc406Sopenharmony_ci}
2510