1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci   Copyright (C) 2000-2003 Jochen Eisinger <jochen.eisinger@gmx.net>
3141cc406Sopenharmony_ci   This file is part of the SANE package.
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
6141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
7141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
8141cc406Sopenharmony_ci   License, or (at your option) any later version.
9141cc406Sopenharmony_ci
10141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
11141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
12141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13141cc406Sopenharmony_ci   General Public License for more details.
14141cc406Sopenharmony_ci
15141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
16141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
19141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
22141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
23141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
24141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
25141cc406Sopenharmony_ci   account of linking the SANE library code into it.
26141cc406Sopenharmony_ci
27141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
28141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
29141cc406Sopenharmony_ci   License.
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
32141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
33141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
36141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
37141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
38141cc406Sopenharmony_ci
39141cc406Sopenharmony_ci   This file implements a SANE backend for Mustek PP flatbed scanners.  */
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci#include "../include/sane/config.h"
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci#if defined(HAVE_STDLIB_H)
44141cc406Sopenharmony_ci# include <stdlib.h>
45141cc406Sopenharmony_ci#endif
46141cc406Sopenharmony_ci#include <stdio.h>
47141cc406Sopenharmony_ci#include <ctype.h>
48141cc406Sopenharmony_ci#include <errno.h>
49141cc406Sopenharmony_ci#include <limits.h>
50141cc406Sopenharmony_ci#include <signal.h>
51141cc406Sopenharmony_ci#if defined(HAVE_STRING_H)
52141cc406Sopenharmony_ci# include <string.h>
53141cc406Sopenharmony_ci#elif defined(HAVE_STRINGS_H)
54141cc406Sopenharmony_ci# include <strings.h>
55141cc406Sopenharmony_ci#endif
56141cc406Sopenharmony_ci#if defined(HAVE_UNISTD_H)
57141cc406Sopenharmony_ci# include <unistd.h>
58141cc406Sopenharmony_ci#endif
59141cc406Sopenharmony_ci#include <math.h>
60141cc406Sopenharmony_ci#include <fcntl.h>
61141cc406Sopenharmony_ci#include <time.h>
62141cc406Sopenharmony_ci#if defined(HAVE_SYS_TIME_H)
63141cc406Sopenharmony_ci# include <sys/time.h>
64141cc406Sopenharmony_ci#endif
65141cc406Sopenharmony_ci#if defined(HAVE_SYS_TYPES_H)
66141cc406Sopenharmony_ci# include <sys/types.h>
67141cc406Sopenharmony_ci#endif
68141cc406Sopenharmony_ci#include <sys/wait.h>
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_ci#define BACKEND_NAME	mustek_pp
71141cc406Sopenharmony_ci
72141cc406Sopenharmony_ci#include "../include/sane/sane.h"
73141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
74141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
77141cc406Sopenharmony_ci
78141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
79141cc406Sopenharmony_ci#define MUSTEK_PP_CONFIG_FILE "mustek_pp.conf"
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_ci#include "../include/sane/sanei_pa4s2.h"
82141cc406Sopenharmony_ci
83141cc406Sopenharmony_ci#include "mustek_pp.h"
84141cc406Sopenharmony_ci#include "mustek_pp_drivers.h"
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_ci#define MIN(a,b)	((a) < (b) ? (a) : (b))
87141cc406Sopenharmony_ci
88141cc406Sopenharmony_ci/* converts millimeter to pixels at a given resolution */
89141cc406Sopenharmony_ci#define	MM_TO_PIXEL(mm, dpi)	(((float )mm * 5.0 / 127.0) * (float)dpi)
90141cc406Sopenharmony_ci   /* and back */
91141cc406Sopenharmony_ci#define PIXEL_TO_MM(pixel, dpi) (((float )pixel / (float )dpi) * 127.0 / 5.0)
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_ci/* if you change the source, please set MUSTEK_PP_STATE to "devel". Do *not*
94141cc406Sopenharmony_ci * change the MUSTEK_PP_BUILD. */
95141cc406Sopenharmony_ci#define MUSTEK_PP_BUILD	13
96141cc406Sopenharmony_ci#define MUSTEK_PP_STATE	"beta"
97141cc406Sopenharmony_ci
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_ci/* auth callback... since basic user authentication is done by saned, this
100141cc406Sopenharmony_ci * callback mechanism isn't used */
101141cc406Sopenharmony_ciSANE_Auth_Callback sane_auth;
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci/* count of present devices */
104141cc406Sopenharmony_cistatic int num_devices = 0;
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_ci/* list of present devices */
107141cc406Sopenharmony_cistatic Mustek_pp_Device *devlist = NULL;
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_ci/* temporary array of configuration options used during device attachment */
110141cc406Sopenharmony_cistatic Mustek_pp_config_option *cfgoptions = NULL;
111141cc406Sopenharmony_cistatic int numcfgoptions = 0;
112141cc406Sopenharmony_ci
113141cc406Sopenharmony_ci/* list of pointers to the SANE_Device structures of the Mustek_pp_Devices */
114141cc406Sopenharmony_cistatic SANE_Device **devarray = NULL;
115141cc406Sopenharmony_ci
116141cc406Sopenharmony_ci/* currently active Handles */
117141cc406Sopenharmony_cistatic Mustek_pp_Handle *first_hndl = NULL;
118141cc406Sopenharmony_ci
119141cc406Sopenharmony_cistatic SANE_String_Const       mustek_pp_modes[4] = {SANE_VALUE_SCAN_MODE_LINEART, SANE_VALUE_SCAN_MODE_GRAY, SANE_VALUE_SCAN_MODE_COLOR, NULL};
120141cc406Sopenharmony_cistatic SANE_Word               mustek_pp_modes_size = 10;
121141cc406Sopenharmony_ci
122141cc406Sopenharmony_cistatic SANE_String_Const       mustek_pp_speeds[6] = {"Slowest", "Slower", "Normal", "Faster", "Fastest", NULL};
123141cc406Sopenharmony_cistatic SANE_Word               mustek_pp_speeds_size = 8;
124141cc406Sopenharmony_cistatic SANE_Word               mustek_pp_depths[5] = {4, 8, 10, 12, 16};
125141cc406Sopenharmony_ci
126141cc406Sopenharmony_ci/* prototypes */
127141cc406Sopenharmony_cistatic void free_cfg_options(int *numoptions, Mustek_pp_config_option** options);
128141cc406Sopenharmony_cistatic SANE_Status do_eof(Mustek_pp_Handle *hndl);
129141cc406Sopenharmony_cistatic SANE_Status do_stop(Mustek_pp_Handle *hndl);
130141cc406Sopenharmony_cistatic int reader_process (Mustek_pp_Handle * hndl, int pipe);
131141cc406Sopenharmony_cistatic SANE_Status sane_attach(SANE_String_Const port, SANE_String_Const name,
132141cc406Sopenharmony_ci			SANE_Int driver, SANE_Int info);
133141cc406Sopenharmony_cistatic void init_options(Mustek_pp_Handle *hndl);
134141cc406Sopenharmony_cistatic void attach_device(SANE_String *driver, SANE_String *name,
135141cc406Sopenharmony_ci		   SANE_String *port, SANE_String *option_ta);
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_ci
138141cc406Sopenharmony_ci/*
139141cc406Sopenharmony_ci * Auxiliary function for freeing arrays of configuration options,
140141cc406Sopenharmony_ci */
141141cc406Sopenharmony_cistatic void
142141cc406Sopenharmony_cifree_cfg_options(int *numoptions, Mustek_pp_config_option** options)
143141cc406Sopenharmony_ci{
144141cc406Sopenharmony_ci   int i;
145141cc406Sopenharmony_ci   if (*numoptions)
146141cc406Sopenharmony_ci   {
147141cc406Sopenharmony_ci      for (i=0; i<*numoptions; ++i)
148141cc406Sopenharmony_ci      {
149141cc406Sopenharmony_ci         free ((*options)[i].name);
150141cc406Sopenharmony_ci         free ((*options)[i].value);
151141cc406Sopenharmony_ci      }
152141cc406Sopenharmony_ci      free (*options);
153141cc406Sopenharmony_ci   }
154141cc406Sopenharmony_ci   *options = NULL;
155141cc406Sopenharmony_ci   *numoptions = 0;
156141cc406Sopenharmony_ci}
157141cc406Sopenharmony_ci
158141cc406Sopenharmony_ci/* do_eof:
159141cc406Sopenharmony_ci * 	closes the pipeline
160141cc406Sopenharmony_ci *
161141cc406Sopenharmony_ci * Description:
162141cc406Sopenharmony_ci * 	closes the pipe (read-only end)
163141cc406Sopenharmony_ci */
164141cc406Sopenharmony_cistatic SANE_Status
165141cc406Sopenharmony_cido_eof (Mustek_pp_Handle *hndl)
166141cc406Sopenharmony_ci{
167141cc406Sopenharmony_ci	if (hndl->pipe >= 0) {
168141cc406Sopenharmony_ci
169141cc406Sopenharmony_ci		close (hndl->pipe);
170141cc406Sopenharmony_ci		hndl->pipe = -1;
171141cc406Sopenharmony_ci	}
172141cc406Sopenharmony_ci
173141cc406Sopenharmony_ci	return SANE_STATUS_EOF;
174141cc406Sopenharmony_ci}
175141cc406Sopenharmony_ci
176141cc406Sopenharmony_ci/* do_stop:
177141cc406Sopenharmony_ci * 	ends the reader_process and stops the scanner
178141cc406Sopenharmony_ci *
179141cc406Sopenharmony_ci * Description:
180141cc406Sopenharmony_ci * 	kills the reader process with a SIGTERM and cancels the scanner
181141cc406Sopenharmony_ci */
182141cc406Sopenharmony_cistatic SANE_Status
183141cc406Sopenharmony_cido_stop(Mustek_pp_Handle *hndl)
184141cc406Sopenharmony_ci{
185141cc406Sopenharmony_ci
186141cc406Sopenharmony_ci	int	exit_status;
187141cc406Sopenharmony_ci
188141cc406Sopenharmony_ci	do_eof (hndl);
189141cc406Sopenharmony_ci
190141cc406Sopenharmony_ci	if (hndl->reader > 0) {
191141cc406Sopenharmony_ci
192141cc406Sopenharmony_ci		DBG (3, "do_stop: terminating reader process\n");
193141cc406Sopenharmony_ci		kill (hndl->reader, SIGTERM);
194141cc406Sopenharmony_ci
195141cc406Sopenharmony_ci		while (wait (&exit_status) != hndl->reader);
196141cc406Sopenharmony_ci
197141cc406Sopenharmony_ci		DBG ((exit_status == SANE_STATUS_GOOD ? 3 : 1),
198141cc406Sopenharmony_ci			       "do_stop: reader_process terminated with status ``%s''\n",
199141cc406Sopenharmony_ci			       sane_strstatus(exit_status));
200141cc406Sopenharmony_ci		hndl->reader = 0;
201141cc406Sopenharmony_ci		hndl->dev->func->stop (hndl);
202141cc406Sopenharmony_ci
203141cc406Sopenharmony_ci		return exit_status;
204141cc406Sopenharmony_ci
205141cc406Sopenharmony_ci	}
206141cc406Sopenharmony_ci
207141cc406Sopenharmony_ci	hndl->dev->func->stop (hndl);
208141cc406Sopenharmony_ci
209141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
210141cc406Sopenharmony_ci}
211141cc406Sopenharmony_ci
212141cc406Sopenharmony_ci/* sigterm_handler:
213141cc406Sopenharmony_ci * 	cancel scanner when receiving a SIGTERM
214141cc406Sopenharmony_ci *
215141cc406Sopenharmony_ci * Description:
216141cc406Sopenharmony_ci *	just exit... reader_process takes care that nothing bad will happen
217141cc406Sopenharmony_ci *
218141cc406Sopenharmony_ci * EDG - Jan 14, 2004:
219141cc406Sopenharmony_ci *      Make sure that the parport is released again by the child process
220141cc406Sopenharmony_ci *      under all circumstances, because otherwise the parent process may no
221141cc406Sopenharmony_ci *      longer be able to claim it (they share the same file descriptor, and
222141cc406Sopenharmony_ci *      the kernel doesn't release the child's claim because the file
223141cc406Sopenharmony_ci *      descriptor isn't cleaned up). If that would happen, the lamp may stay
224141cc406Sopenharmony_ci *      on and may not return to its home position, unless the scanner
225141cc406Sopenharmony_ci *      frontend is restarted.
226141cc406Sopenharmony_ci *      (This happens only when sanei_pa4s2 uses libieee1284 AND
227141cc406Sopenharmony_ci *      libieee1284 goes via /dev/parportX).
228141cc406Sopenharmony_ci *
229141cc406Sopenharmony_ci */
230141cc406Sopenharmony_cistatic int fd_to_release = 0;
231141cc406Sopenharmony_ci/*ARGSUSED*/
232141cc406Sopenharmony_cistatic void
233141cc406Sopenharmony_cisigterm_handler (int signal __UNUSED__)
234141cc406Sopenharmony_ci{
235141cc406Sopenharmony_ci	sanei_pa4s2_enable(fd_to_release, SANE_FALSE);
236141cc406Sopenharmony_ci	_exit (SANE_STATUS_GOOD);
237141cc406Sopenharmony_ci}
238141cc406Sopenharmony_ci
239141cc406Sopenharmony_ci/* reader_process:
240141cc406Sopenharmony_ci * 	receives data from the scanner and stuff it into the pipeline
241141cc406Sopenharmony_ci *
242141cc406Sopenharmony_ci * Description:
243141cc406Sopenharmony_ci * 	The signal handle for SIGTERM is initialized.
244141cc406Sopenharmony_ci *
245141cc406Sopenharmony_ci */
246141cc406Sopenharmony_cistatic int
247141cc406Sopenharmony_cireader_process (Mustek_pp_Handle * hndl, int pipe)
248141cc406Sopenharmony_ci{
249141cc406Sopenharmony_ci	sigset_t	sigterm_set;
250141cc406Sopenharmony_ci	struct SIGACTION act;
251141cc406Sopenharmony_ci	FILE *fp;
252141cc406Sopenharmony_ci	SANE_Status status;
253141cc406Sopenharmony_ci	int line;
254141cc406Sopenharmony_ci	int size, elem;
255141cc406Sopenharmony_ci
256141cc406Sopenharmony_ci	SANE_Byte *buffer;
257141cc406Sopenharmony_ci
258141cc406Sopenharmony_ci	sigemptyset (&sigterm_set);
259141cc406Sopenharmony_ci	sigaddset (&sigterm_set, SIGTERM);
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_ci	if (!(buffer = malloc (hndl->params.bytes_per_line)))
262141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
263141cc406Sopenharmony_ci
264141cc406Sopenharmony_ci	if (!(fp = fdopen(pipe, "w")))
265141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
266141cc406Sopenharmony_ci
267141cc406Sopenharmony_ci	fd_to_release = hndl->fd;
268141cc406Sopenharmony_ci	memset (&act, 0, sizeof(act));
269141cc406Sopenharmony_ci	act.sa_handler = sigterm_handler;
270141cc406Sopenharmony_ci	sigaction (SIGTERM, &act, NULL);
271141cc406Sopenharmony_ci
272141cc406Sopenharmony_ci	if ((status = hndl->dev->func->start (hndl)) != SANE_STATUS_GOOD)
273141cc406Sopenharmony_ci		return status;
274141cc406Sopenharmony_ci
275141cc406Sopenharmony_ci        size = hndl->params.bytes_per_line;
276141cc406Sopenharmony_ci  	elem = 1;
277141cc406Sopenharmony_ci
278141cc406Sopenharmony_ci	for (line=0; line<hndl->params.lines ; line++) {
279141cc406Sopenharmony_ci
280141cc406Sopenharmony_ci		sigprocmask (SIG_BLOCK, &sigterm_set, NULL);
281141cc406Sopenharmony_ci
282141cc406Sopenharmony_ci		hndl->dev->func->read (hndl, buffer);
283141cc406Sopenharmony_ci
284141cc406Sopenharmony_ci                if (getppid() == 1) {
285141cc406Sopenharmony_ci                    /* The parent process has died. Stop the scan (to make
286141cc406Sopenharmony_ci                       sure that the lamp is off and returns home). This is
287141cc406Sopenharmony_ci                       a safety measure to make sure that we don't break
288141cc406Sopenharmony_ci                       the scanner in case the frontend crashes. */
289141cc406Sopenharmony_ci		    DBG (1, "reader_process: front-end died; aborting.\n");
290141cc406Sopenharmony_ci                    hndl->dev->func->stop (hndl);
291141cc406Sopenharmony_ci                    return SANE_STATUS_CANCELLED;
292141cc406Sopenharmony_ci                }
293141cc406Sopenharmony_ci
294141cc406Sopenharmony_ci		sigprocmask (SIG_UNBLOCK, &sigterm_set, NULL);
295141cc406Sopenharmony_ci
296141cc406Sopenharmony_ci		fwrite (buffer, size, elem, fp);
297141cc406Sopenharmony_ci	}
298141cc406Sopenharmony_ci
299141cc406Sopenharmony_ci	fclose (fp);
300141cc406Sopenharmony_ci
301141cc406Sopenharmony_ci	free (buffer);
302141cc406Sopenharmony_ci
303141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
304141cc406Sopenharmony_ci}
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci
308141cc406Sopenharmony_ci/* sane_attach:
309141cc406Sopenharmony_ci * 	adds a new entry to the Mustek_pp_Device *devlist list
310141cc406Sopenharmony_ci *
311141cc406Sopenharmony_ci * Description:
312141cc406Sopenharmony_ci * 	After memory for a new device entry is allocated, the
313141cc406Sopenharmony_ci * 	parameters for the device are determined by a call to
314141cc406Sopenharmony_ci * 	capabilities().
315141cc406Sopenharmony_ci *
316141cc406Sopenharmony_ci * 	Afterwards the new device entry is inserted into the
317141cc406Sopenharmony_ci * 	devlist
318141cc406Sopenharmony_ci *
319141cc406Sopenharmony_ci */
320141cc406Sopenharmony_cistatic SANE_Status
321141cc406Sopenharmony_cisane_attach (SANE_String_Const port, SANE_String_Const name, SANE_Int driver, SANE_Int info)
322141cc406Sopenharmony_ci{
323141cc406Sopenharmony_ci	Mustek_pp_Device	*dev;
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_ci	DBG (3, "sane_attach: attaching device ``%s'' to port %s (driver %s v%s by %s)\n",
326141cc406Sopenharmony_ci			name, port, Mustek_pp_Drivers[driver].driver,
327141cc406Sopenharmony_ci				Mustek_pp_Drivers[driver].version,
328141cc406Sopenharmony_ci				Mustek_pp_Drivers[driver].author);
329141cc406Sopenharmony_ci
330141cc406Sopenharmony_ci	if ((dev = malloc (sizeof (Mustek_pp_Device))) == NULL) {
331141cc406Sopenharmony_ci
332141cc406Sopenharmony_ci		DBG (1, "sane_attach: not enough free memory\n");
333141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
334141cc406Sopenharmony_ci
335141cc406Sopenharmony_ci	}
336141cc406Sopenharmony_ci
337141cc406Sopenharmony_ci	memset (dev, 0, sizeof (Mustek_pp_Device));
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci	memset (&dev->sane, 0, sizeof (SANE_Device));
340141cc406Sopenharmony_ci
341141cc406Sopenharmony_ci	dev->func = &Mustek_pp_Drivers[driver];
342141cc406Sopenharmony_ci
343141cc406Sopenharmony_ci	dev->sane.name = dev->name = strdup (name);
344141cc406Sopenharmony_ci	dev->port = strdup (port);
345141cc406Sopenharmony_ci        dev->info = info; /* Modified by EDG */
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci        /* Transfer the options parsed from the configuration file */
348141cc406Sopenharmony_ci        dev->numcfgoptions = numcfgoptions;
349141cc406Sopenharmony_ci        dev->cfgoptions = cfgoptions;
350141cc406Sopenharmony_ci        numcfgoptions = 0;
351141cc406Sopenharmony_ci        cfgoptions = NULL;
352141cc406Sopenharmony_ci
353141cc406Sopenharmony_ci	dev->func->capabilities (info, &dev->model, &dev->vendor, &dev->type,
354141cc406Sopenharmony_ci			&dev->maxres, &dev->minres, &dev->maxhsize, &dev->maxvsize,
355141cc406Sopenharmony_ci			&dev->caps);
356141cc406Sopenharmony_ci
357141cc406Sopenharmony_ci	dev->sane.model = dev->model;
358141cc406Sopenharmony_ci	dev->sane.vendor = dev->vendor;
359141cc406Sopenharmony_ci	dev->sane.type = dev->type;
360141cc406Sopenharmony_ci
361141cc406Sopenharmony_ci	dev->next = devlist;
362141cc406Sopenharmony_ci	devlist = dev;
363141cc406Sopenharmony_ci
364141cc406Sopenharmony_ci	num_devices++;
365141cc406Sopenharmony_ci
366141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
367141cc406Sopenharmony_ci}
368141cc406Sopenharmony_ci
369141cc406Sopenharmony_ci
370141cc406Sopenharmony_ci/* init_options:
371141cc406Sopenharmony_ci * 	Sets up the option descriptors for a device
372141cc406Sopenharmony_ci *
373141cc406Sopenharmony_ci * Description:
374141cc406Sopenharmony_ci */
375141cc406Sopenharmony_cistatic void
376141cc406Sopenharmony_ciinit_options(Mustek_pp_Handle *hndl)
377141cc406Sopenharmony_ci{
378141cc406Sopenharmony_ci  int i;
379141cc406Sopenharmony_ci
380141cc406Sopenharmony_ci  memset (hndl->opt, 0, sizeof (hndl->opt));
381141cc406Sopenharmony_ci  memset (hndl->val, 0, sizeof (hndl->val));
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_ci  for (i = 0; i < NUM_OPTIONS; ++i)
384141cc406Sopenharmony_ci    {
385141cc406Sopenharmony_ci      hndl->opt[i].size = sizeof (SANE_Word);
386141cc406Sopenharmony_ci      hndl->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
387141cc406Sopenharmony_ci    }
388141cc406Sopenharmony_ci
389141cc406Sopenharmony_ci  hndl->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
390141cc406Sopenharmony_ci  hndl->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
391141cc406Sopenharmony_ci  hndl->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
392141cc406Sopenharmony_ci  hndl->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
393141cc406Sopenharmony_ci  hndl->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
394141cc406Sopenharmony_ci  hndl->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
395141cc406Sopenharmony_ci
396141cc406Sopenharmony_ci  /* "Mode" group: */
397141cc406Sopenharmony_ci
398141cc406Sopenharmony_ci  hndl->opt[OPT_MODE_GROUP].title = "Scan Mode";
399141cc406Sopenharmony_ci  hndl->opt[OPT_MODE_GROUP].desc = "";
400141cc406Sopenharmony_ci  hndl->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
401141cc406Sopenharmony_ci  hndl->opt[OPT_MODE_GROUP].cap = 0;
402141cc406Sopenharmony_ci  hndl->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
403141cc406Sopenharmony_ci  hndl->opt[OPT_MODE_GROUP].size = 0;
404141cc406Sopenharmony_ci
405141cc406Sopenharmony_ci  /* scan mode */
406141cc406Sopenharmony_ci  hndl->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
407141cc406Sopenharmony_ci  hndl->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
408141cc406Sopenharmony_ci  hndl->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
409141cc406Sopenharmony_ci  hndl->opt[OPT_MODE].type = SANE_TYPE_STRING;
410141cc406Sopenharmony_ci  hndl->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
411141cc406Sopenharmony_ci  hndl->opt[OPT_MODE].size = mustek_pp_modes_size;
412141cc406Sopenharmony_ci  hndl->opt[OPT_MODE].constraint.string_list = mustek_pp_modes;
413141cc406Sopenharmony_ci  hndl->val[OPT_MODE].s = strdup (mustek_pp_modes[2]);
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci  /* resolution */
416141cc406Sopenharmony_ci  hndl->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
417141cc406Sopenharmony_ci  hndl->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
418141cc406Sopenharmony_ci  hndl->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
419141cc406Sopenharmony_ci  hndl->opt[OPT_RESOLUTION].type = SANE_TYPE_FIXED;
420141cc406Sopenharmony_ci  hndl->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
421141cc406Sopenharmony_ci  hndl->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
422141cc406Sopenharmony_ci  hndl->opt[OPT_RESOLUTION].constraint.range = &hndl->dpi_range;
423141cc406Sopenharmony_ci  hndl->val[OPT_RESOLUTION].w = SANE_FIX (hndl->dev->minres);
424141cc406Sopenharmony_ci  hndl->dpi_range.min = SANE_FIX (hndl->dev->minres);
425141cc406Sopenharmony_ci  hndl->dpi_range.max = SANE_FIX (hndl->dev->maxres);
426141cc406Sopenharmony_ci  hndl->dpi_range.quant = SANE_FIX (1);
427141cc406Sopenharmony_ci
428141cc406Sopenharmony_ci  /* speed */
429141cc406Sopenharmony_ci  hndl->opt[OPT_SPEED].name = SANE_NAME_SCAN_SPEED;
430141cc406Sopenharmony_ci  hndl->opt[OPT_SPEED].title = SANE_TITLE_SCAN_SPEED;
431141cc406Sopenharmony_ci  hndl->opt[OPT_SPEED].desc = SANE_DESC_SCAN_SPEED;
432141cc406Sopenharmony_ci  hndl->opt[OPT_SPEED].type = SANE_TYPE_STRING;
433141cc406Sopenharmony_ci  hndl->opt[OPT_SPEED].size = mustek_pp_speeds_size;
434141cc406Sopenharmony_ci  hndl->opt[OPT_SPEED].constraint_type = SANE_CONSTRAINT_STRING_LIST;
435141cc406Sopenharmony_ci  hndl->opt[OPT_SPEED].constraint.string_list = mustek_pp_speeds;
436141cc406Sopenharmony_ci  hndl->val[OPT_SPEED].s = strdup (mustek_pp_speeds[2]);
437141cc406Sopenharmony_ci
438141cc406Sopenharmony_ci  if (! (hndl->dev->caps & CAP_SPEED_SELECT))
439141cc406Sopenharmony_ci	  hndl->opt[OPT_SPEED].cap |= SANE_CAP_INACTIVE;
440141cc406Sopenharmony_ci
441141cc406Sopenharmony_ci  /* preview */
442141cc406Sopenharmony_ci  hndl->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
443141cc406Sopenharmony_ci  hndl->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
444141cc406Sopenharmony_ci  hndl->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
445141cc406Sopenharmony_ci  hndl->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
446141cc406Sopenharmony_ci  hndl->val[OPT_PREVIEW].w = SANE_FALSE;
447141cc406Sopenharmony_ci
448141cc406Sopenharmony_ci  /* gray preview */
449141cc406Sopenharmony_ci  hndl->opt[OPT_GRAY_PREVIEW].name = SANE_NAME_GRAY_PREVIEW;
450141cc406Sopenharmony_ci  hndl->opt[OPT_GRAY_PREVIEW].title = SANE_TITLE_GRAY_PREVIEW;
451141cc406Sopenharmony_ci  hndl->opt[OPT_GRAY_PREVIEW].desc = SANE_DESC_GRAY_PREVIEW;
452141cc406Sopenharmony_ci  hndl->opt[OPT_GRAY_PREVIEW].type = SANE_TYPE_BOOL;
453141cc406Sopenharmony_ci  hndl->val[OPT_GRAY_PREVIEW].w = SANE_FALSE;
454141cc406Sopenharmony_ci
455141cc406Sopenharmony_ci  /* color dept */
456141cc406Sopenharmony_ci  hndl->opt[OPT_DEPTH].name = SANE_NAME_BIT_DEPTH;
457141cc406Sopenharmony_ci  hndl->opt[OPT_DEPTH].title = SANE_TITLE_BIT_DEPTH;
458141cc406Sopenharmony_ci  hndl->opt[OPT_DEPTH].desc =
459141cc406Sopenharmony_ci	  "Number of bits per sample for color scans, typical values are 8 for truecolor (24bpp)"
460141cc406Sopenharmony_ci	  "up to 16 for far-to-many-color (48bpp).";
461141cc406Sopenharmony_ci  hndl->opt[OPT_DEPTH].type = SANE_TYPE_INT;
462141cc406Sopenharmony_ci  hndl->opt[OPT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
463141cc406Sopenharmony_ci  hndl->opt[OPT_DEPTH].constraint.word_list = mustek_pp_depths;
464141cc406Sopenharmony_ci  hndl->opt[OPT_DEPTH].unit = SANE_UNIT_BIT;
465141cc406Sopenharmony_ci  hndl->opt[OPT_DEPTH].size = sizeof(SANE_Word);
466141cc406Sopenharmony_ci  hndl->val[OPT_DEPTH].w = 8;
467141cc406Sopenharmony_ci
468141cc406Sopenharmony_ci  if ( !(hndl->dev->caps & CAP_DEPTH))
469141cc406Sopenharmony_ci	  hndl->opt[OPT_DEPTH].cap |= SANE_CAP_INACTIVE;
470141cc406Sopenharmony_ci
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci  /* "Geometry" group: */
473141cc406Sopenharmony_ci
474141cc406Sopenharmony_ci  hndl->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
475141cc406Sopenharmony_ci  hndl->opt[OPT_GEOMETRY_GROUP].desc = "";
476141cc406Sopenharmony_ci  hndl->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
477141cc406Sopenharmony_ci  hndl->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
478141cc406Sopenharmony_ci  hndl->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
479141cc406Sopenharmony_ci  hndl->opt[OPT_GEOMETRY_GROUP].size = 0;
480141cc406Sopenharmony_ci
481141cc406Sopenharmony_ci  /* top-left x */
482141cc406Sopenharmony_ci  hndl->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
483141cc406Sopenharmony_ci  hndl->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
484141cc406Sopenharmony_ci  hndl->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
485141cc406Sopenharmony_ci  hndl->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
486141cc406Sopenharmony_ci  hndl->opt[OPT_TL_X].unit = SANE_UNIT_MM;
487141cc406Sopenharmony_ci  hndl->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
488141cc406Sopenharmony_ci  hndl->opt[OPT_TL_X].constraint.range = &hndl->x_range;
489141cc406Sopenharmony_ci  hndl->x_range.min = SANE_FIX (0);
490141cc406Sopenharmony_ci  hndl->x_range.max = SANE_FIX (PIXEL_TO_MM(hndl->dev->maxhsize,hndl->dev->maxres));
491141cc406Sopenharmony_ci  hndl->x_range.quant = 0;
492141cc406Sopenharmony_ci  hndl->val[OPT_TL_X].w = hndl->x_range.min;
493141cc406Sopenharmony_ci
494141cc406Sopenharmony_ci  /* top-left y */
495141cc406Sopenharmony_ci  hndl->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
496141cc406Sopenharmony_ci  hndl->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
497141cc406Sopenharmony_ci  hndl->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
498141cc406Sopenharmony_ci  hndl->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
499141cc406Sopenharmony_ci  hndl->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
500141cc406Sopenharmony_ci  hndl->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
501141cc406Sopenharmony_ci  hndl->opt[OPT_TL_Y].constraint.range = &hndl->y_range;
502141cc406Sopenharmony_ci  hndl->y_range.min = SANE_FIX(0);
503141cc406Sopenharmony_ci  hndl->y_range.max = SANE_FIX(PIXEL_TO_MM(hndl->dev->maxvsize,hndl->dev->maxres));
504141cc406Sopenharmony_ci  hndl->y_range.quant = 0;
505141cc406Sopenharmony_ci  hndl->val[OPT_TL_Y].w = hndl->y_range.min;
506141cc406Sopenharmony_ci
507141cc406Sopenharmony_ci  /* bottom-right x */
508141cc406Sopenharmony_ci  hndl->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
509141cc406Sopenharmony_ci  hndl->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
510141cc406Sopenharmony_ci  hndl->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
511141cc406Sopenharmony_ci  hndl->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
512141cc406Sopenharmony_ci  hndl->opt[OPT_BR_X].unit = SANE_UNIT_MM;
513141cc406Sopenharmony_ci  hndl->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
514141cc406Sopenharmony_ci  hndl->opt[OPT_BR_X].constraint.range = &hndl->x_range;
515141cc406Sopenharmony_ci  hndl->val[OPT_BR_X].w = hndl->x_range.max;
516141cc406Sopenharmony_ci
517141cc406Sopenharmony_ci  /* bottom-right y */
518141cc406Sopenharmony_ci  hndl->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
519141cc406Sopenharmony_ci  hndl->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
520141cc406Sopenharmony_ci  hndl->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
521141cc406Sopenharmony_ci  hndl->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
522141cc406Sopenharmony_ci  hndl->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
523141cc406Sopenharmony_ci  hndl->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
524141cc406Sopenharmony_ci  hndl->opt[OPT_BR_Y].constraint.range = &hndl->y_range;
525141cc406Sopenharmony_ci  hndl->val[OPT_BR_Y].w = hndl->y_range.max;
526141cc406Sopenharmony_ci
527141cc406Sopenharmony_ci  /* "Enhancement" group: */
528141cc406Sopenharmony_ci
529141cc406Sopenharmony_ci  hndl->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
530141cc406Sopenharmony_ci  hndl->opt[OPT_ENHANCEMENT_GROUP].desc = "";
531141cc406Sopenharmony_ci  hndl->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
532141cc406Sopenharmony_ci  hndl->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
533141cc406Sopenharmony_ci  hndl->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
534141cc406Sopenharmony_ci  hndl->opt[OPT_ENHANCEMENT_GROUP].size = 0;
535141cc406Sopenharmony_ci
536141cc406Sopenharmony_ci
537141cc406Sopenharmony_ci  /* custom-gamma table */
538141cc406Sopenharmony_ci  hndl->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA;
539141cc406Sopenharmony_ci  hndl->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
540141cc406Sopenharmony_ci  hndl->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA;
541141cc406Sopenharmony_ci  hndl->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL;
542141cc406Sopenharmony_ci  hndl->val[OPT_CUSTOM_GAMMA].w = SANE_FALSE;
543141cc406Sopenharmony_ci
544141cc406Sopenharmony_ci  if ( !(hndl->dev->caps & CAP_GAMMA_CORRECT))
545141cc406Sopenharmony_ci	  hndl->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
546141cc406Sopenharmony_ci
547141cc406Sopenharmony_ci  /* grayscale gamma vector */
548141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
549141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
550141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
551141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
552141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
553141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
554141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR].size = 256 * sizeof (SANE_Word);
555141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
556141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR].constraint.range = &hndl->gamma_range;
557141cc406Sopenharmony_ci  hndl->val[OPT_GAMMA_VECTOR].wa = &hndl->gamma_table[0][0];
558141cc406Sopenharmony_ci
559141cc406Sopenharmony_ci  /* red gamma vector */
560141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
561141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
562141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
563141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
564141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
565141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
566141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof (SANE_Word);
567141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
568141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_R].constraint.range = &hndl->gamma_range;
569141cc406Sopenharmony_ci  hndl->val[OPT_GAMMA_VECTOR_R].wa = &hndl->gamma_table[1][0];
570141cc406Sopenharmony_ci
571141cc406Sopenharmony_ci  /* green gamma vector */
572141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
573141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
574141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
575141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
576141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
577141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
578141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof (SANE_Word);
579141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
580141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_G].constraint.range = &hndl->gamma_range;
581141cc406Sopenharmony_ci  hndl->val[OPT_GAMMA_VECTOR_G].wa = &hndl->gamma_table[2][0];
582141cc406Sopenharmony_ci
583141cc406Sopenharmony_ci  /* blue gamma vector */
584141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
585141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
586141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
587141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
588141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
589141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
590141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof (SANE_Word);
591141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
592141cc406Sopenharmony_ci  hndl->opt[OPT_GAMMA_VECTOR_B].constraint.range = &hndl->gamma_range;
593141cc406Sopenharmony_ci  hndl->val[OPT_GAMMA_VECTOR_B].wa = &hndl->gamma_table[3][0];
594141cc406Sopenharmony_ci
595141cc406Sopenharmony_ci  hndl->gamma_range.min = 0;
596141cc406Sopenharmony_ci  hndl->gamma_range.max = 255;
597141cc406Sopenharmony_ci  hndl->gamma_range.quant = 1;
598141cc406Sopenharmony_ci
599141cc406Sopenharmony_ci  hndl->opt[OPT_INVERT].name = SANE_NAME_NEGATIVE;
600141cc406Sopenharmony_ci  hndl->opt[OPT_INVERT].title = SANE_TITLE_NEGATIVE;
601141cc406Sopenharmony_ci  hndl->opt[OPT_INVERT].desc = SANE_DESC_NEGATIVE;
602141cc406Sopenharmony_ci  hndl->opt[OPT_INVERT].type = SANE_TYPE_BOOL;
603141cc406Sopenharmony_ci  hndl->val[OPT_INVERT].w = SANE_FALSE;
604141cc406Sopenharmony_ci
605141cc406Sopenharmony_ci  if (! (hndl->dev->caps & CAP_INVERT))
606141cc406Sopenharmony_ci	  hndl->opt[OPT_INVERT].cap |= SANE_CAP_INACTIVE;
607141cc406Sopenharmony_ci
608141cc406Sopenharmony_ci
609141cc406Sopenharmony_ci}
610141cc406Sopenharmony_ci
611141cc406Sopenharmony_ci/* attach_device:
612141cc406Sopenharmony_ci * 	Attempts to attach a device to the list after parsing of a section
613141cc406Sopenharmony_ci *      of the configuration file.
614141cc406Sopenharmony_ci *
615141cc406Sopenharmony_ci * Description:
616141cc406Sopenharmony_ci *      After parsing a scanner section of the config file, this function
617141cc406Sopenharmony_ci *      is called to look for a driver with a matching name. When found,
618141cc406Sopenharmony_ci *      this driver is called to initialize the device.
619141cc406Sopenharmony_ci */
620141cc406Sopenharmony_cistatic void
621141cc406Sopenharmony_ciattach_device(SANE_String *driver, SANE_String *name,
622141cc406Sopenharmony_ci              SANE_String *port, SANE_String *option_ta)
623141cc406Sopenharmony_ci{
624141cc406Sopenharmony_ci  int found = 0, driver_no, port_no;
625141cc406Sopenharmony_ci  const char **ports;
626141cc406Sopenharmony_ci
627141cc406Sopenharmony_ci  if (!strcmp (*port, "*"))
628141cc406Sopenharmony_ci    {
629141cc406Sopenharmony_ci      ports = sanei_pa4s2_devices();
630141cc406Sopenharmony_ci      DBG (3, "sanei_init: auto probing port\n");
631141cc406Sopenharmony_ci    }
632141cc406Sopenharmony_ci  else
633141cc406Sopenharmony_ci    {
634141cc406Sopenharmony_ci      ports = malloc (sizeof(char *) * 2);
635141cc406Sopenharmony_ci      ports[0] = *port;
636141cc406Sopenharmony_ci      ports[1] = NULL;
637141cc406Sopenharmony_ci    }
638141cc406Sopenharmony_ci
639141cc406Sopenharmony_ci  for (port_no=0; ports[port_no] != NULL; port_no++)
640141cc406Sopenharmony_ci    {
641141cc406Sopenharmony_ci      for (driver_no=0 ; driver_no<MUSTEK_PP_NUM_DRIVERS ; driver_no++)
642141cc406Sopenharmony_ci        {
643141cc406Sopenharmony_ci          if (strcasecmp (Mustek_pp_Drivers[driver_no].driver, *driver) == 0)
644141cc406Sopenharmony_ci   	     {
645141cc406Sopenharmony_ci   	       Mustek_pp_Drivers[driver_no].init (
646141cc406Sopenharmony_ci   	         (*option_ta == 0 ? CAP_NOTHING : CAP_TA),
647141cc406Sopenharmony_ci   	         ports[port_no], *name, sane_attach);
648141cc406Sopenharmony_ci   	       found = 1;
649141cc406Sopenharmony_ci   	       break;
650141cc406Sopenharmony_ci   	     }
651141cc406Sopenharmony_ci        }
652141cc406Sopenharmony_ci    }
653141cc406Sopenharmony_ci
654141cc406Sopenharmony_ci  free (ports);
655141cc406Sopenharmony_ci
656141cc406Sopenharmony_ci  if (found == 0)
657141cc406Sopenharmony_ci    {
658141cc406Sopenharmony_ci      DBG (1, "sane_init: no scanner detected\n");
659141cc406Sopenharmony_ci      DBG (3, "sane_init: either the driver name ``%s'' is invalid, or no scanner was detected\n", *driver);
660141cc406Sopenharmony_ci    }
661141cc406Sopenharmony_ci
662141cc406Sopenharmony_ci  free (*name);
663141cc406Sopenharmony_ci  free (*port);
664141cc406Sopenharmony_ci  free (*driver);
665141cc406Sopenharmony_ci  if (*option_ta)
666141cc406Sopenharmony_ci    free (*option_ta);
667141cc406Sopenharmony_ci  *name = *port = *driver = *option_ta = 0;
668141cc406Sopenharmony_ci
669141cc406Sopenharmony_ci  /* In case of a successful initialization, the configuration options
670141cc406Sopenharmony_ci     should have been transferred to the device, but this function can
671141cc406Sopenharmony_ci     deal with that. */
672141cc406Sopenharmony_ci  free_cfg_options(&numcfgoptions, &cfgoptions);
673141cc406Sopenharmony_ci}
674141cc406Sopenharmony_ci
675141cc406Sopenharmony_ci/* sane_init:
676141cc406Sopenharmony_ci *	Reads configuration file and registers hardware driver
677141cc406Sopenharmony_ci *
678141cc406Sopenharmony_ci * Description:
679141cc406Sopenharmony_ci * 	in *version_code the SANE version this backend was compiled with and the
680141cc406Sopenharmony_ci * 	version of the backend is returned. The value of authorize is stored in
681141cc406Sopenharmony_ci * 	the global variable sane_auth.
682141cc406Sopenharmony_ci *
683141cc406Sopenharmony_ci * 	Next the configuration file is read. If it isn't present, all drivers
684141cc406Sopenharmony_ci * 	are auto-probed with default values (port 0x378, with and without TA).
685141cc406Sopenharmony_ci *
686141cc406Sopenharmony_ci * 	The configuration file is expected to contain lines of the form
687141cc406Sopenharmony_ci *
688141cc406Sopenharmony_ci * 	  scanner <name> <port> <driver> [<option_ta>]
689141cc406Sopenharmony_ci *
690141cc406Sopenharmony_ci * 	where <name> is a arbitrary name to identify this entry
691141cc406Sopenharmony_ci *            <port> is the port where the scanner is attached to
692141cc406Sopenharmony_ci *            <driver> is the name of the driver to use
693141cc406Sopenharmony_ci *
694141cc406Sopenharmony_ci *      if the optional argument "option_ta" is present the driver uses special
695141cc406Sopenharmony_ci *      parameters fitting for a transparency adapter.
696141cc406Sopenharmony_ci */
697141cc406Sopenharmony_ci
698141cc406Sopenharmony_ciSANE_Status
699141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
700141cc406Sopenharmony_ci{
701141cc406Sopenharmony_ci  FILE *fp;
702141cc406Sopenharmony_ci  char config_line[1024];
703141cc406Sopenharmony_ci  const char *config_line_ptr;
704141cc406Sopenharmony_ci  int line=0, driver_no;
705141cc406Sopenharmony_ci  char *driver = 0, *port = 0, *name = 0, *option_ta = 0;
706141cc406Sopenharmony_ci
707141cc406Sopenharmony_ci  DBG_INIT ();
708141cc406Sopenharmony_ci  DBG (3, "sane-mustek_pp, version 0.%d-%s. build for SANE %s\n",
709141cc406Sopenharmony_ci	MUSTEK_PP_BUILD, MUSTEK_PP_STATE, VERSION);
710141cc406Sopenharmony_ci  DBG (3, "backend by Jochen Eisinger <jochen.eisinger@gmx.net>\n");
711141cc406Sopenharmony_ci
712141cc406Sopenharmony_ci  if (version_code != NULL)
713141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, MUSTEK_PP_BUILD);
714141cc406Sopenharmony_ci
715141cc406Sopenharmony_ci  sane_auth = authorize;
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci
718141cc406Sopenharmony_ci  fp = sanei_config_open (MUSTEK_PP_CONFIG_FILE);
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci  if (fp == NULL)
721141cc406Sopenharmony_ci    {
722141cc406Sopenharmony_ci      char driver_name[64];
723141cc406Sopenharmony_ci      const char **devices = sanei_pa4s2_devices();
724141cc406Sopenharmony_ci      int device_no;
725141cc406Sopenharmony_ci
726141cc406Sopenharmony_ci      DBG (2, "sane_init: could not open configuration file\n");
727141cc406Sopenharmony_ci
728141cc406Sopenharmony_ci      for (device_no = 0; devices[device_no] != NULL; device_no++)
729141cc406Sopenharmony_ci        {
730141cc406Sopenharmony_ci	  DBG (3, "sane_init: trying ``%s''\n", devices[device_no]);
731141cc406Sopenharmony_ci          for (driver_no=0 ; driver_no<MUSTEK_PP_NUM_DRIVERS ; driver_no++)
732141cc406Sopenharmony_ci	    {
733141cc406Sopenharmony_ci	      Mustek_pp_Drivers[driver_no].init(CAP_NOTHING, devices[device_no],
734141cc406Sopenharmony_ci	  	        Mustek_pp_Drivers[driver_no].driver, sane_attach);
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_ci	      snprintf (driver_name, 64, "%s-ta",
737141cc406Sopenharmony_ci		    Mustek_pp_Drivers[driver_no].driver);
738141cc406Sopenharmony_ci
739141cc406Sopenharmony_ci	      Mustek_pp_Drivers[driver_no].init(CAP_TA, devices[device_no],
740141cc406Sopenharmony_ci		        driver_name, sane_attach);
741141cc406Sopenharmony_ci	    }
742141cc406Sopenharmony_ci	}
743141cc406Sopenharmony_ci
744141cc406Sopenharmony_ci      free (devices);
745141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
746141cc406Sopenharmony_ci    }
747141cc406Sopenharmony_ci
748141cc406Sopenharmony_ci  while (sanei_config_read (config_line, 1023, fp))
749141cc406Sopenharmony_ci    {
750141cc406Sopenharmony_ci      line++;
751141cc406Sopenharmony_ci      if ((!*config_line) || (*config_line == '#'))
752141cc406Sopenharmony_ci	continue;
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_ci      config_line_ptr = config_line;
755141cc406Sopenharmony_ci
756141cc406Sopenharmony_ci      if (strncmp(config_line_ptr, "scanner", 7) == 0)
757141cc406Sopenharmony_ci	{
758141cc406Sopenharmony_ci	  config_line_ptr += 7;
759141cc406Sopenharmony_ci
760141cc406Sopenharmony_ci          if (name)
761141cc406Sopenharmony_ci          {
762141cc406Sopenharmony_ci             /* Parsing of previous scanner + options is finished. Attach
763141cc406Sopenharmony_ci                the device before we parse the next section. */
764141cc406Sopenharmony_ci             attach_device(&driver, &name, &port, &option_ta);
765141cc406Sopenharmony_ci          }
766141cc406Sopenharmony_ci
767141cc406Sopenharmony_ci	  config_line_ptr = sanei_config_skip_whitespace (config_line_ptr);
768141cc406Sopenharmony_ci	  if (!*config_line_ptr)
769141cc406Sopenharmony_ci	    {
770141cc406Sopenharmony_ci	      DBG (1, "sane_init: parse error in line %d after ``scanner''\n",
771141cc406Sopenharmony_ci		line);
772141cc406Sopenharmony_ci	      continue;
773141cc406Sopenharmony_ci	    }
774141cc406Sopenharmony_ci
775141cc406Sopenharmony_ci	  config_line_ptr = sanei_config_get_string (config_line_ptr, &name);
776141cc406Sopenharmony_ci	  if ((name == NULL) || (!*name))
777141cc406Sopenharmony_ci	    {
778141cc406Sopenharmony_ci	      DBG (1, "sane_init: parse error in line %d after ``scanner''\n",
779141cc406Sopenharmony_ci		line);
780141cc406Sopenharmony_ci	      if (name != NULL)
781141cc406Sopenharmony_ci		free (name);
782141cc406Sopenharmony_ci	      name = 0;
783141cc406Sopenharmony_ci	      continue;
784141cc406Sopenharmony_ci	    }
785141cc406Sopenharmony_ci
786141cc406Sopenharmony_ci	  config_line_ptr = sanei_config_skip_whitespace (config_line_ptr);
787141cc406Sopenharmony_ci	  if (!*config_line_ptr)
788141cc406Sopenharmony_ci	    {
789141cc406Sopenharmony_ci	      DBG (1, "sane_init: parse error in line %d after "
790141cc406Sopenharmony_ci		"``scanner %s''\n", line, name);
791141cc406Sopenharmony_ci	      free (name);
792141cc406Sopenharmony_ci	      name = 0;
793141cc406Sopenharmony_ci	      continue;
794141cc406Sopenharmony_ci	    }
795141cc406Sopenharmony_ci
796141cc406Sopenharmony_ci	  config_line_ptr = sanei_config_get_string (config_line_ptr, &port);
797141cc406Sopenharmony_ci	  if ((port == NULL) || (!*port))
798141cc406Sopenharmony_ci	    {
799141cc406Sopenharmony_ci	      DBG (1, "sane_init: parse error in line %d after "
800141cc406Sopenharmony_ci		"``scanner %s''\n", line, name);
801141cc406Sopenharmony_ci	      free (name);
802141cc406Sopenharmony_ci	      name = 0;
803141cc406Sopenharmony_ci	      if (port != NULL)
804141cc406Sopenharmony_ci		free (port);
805141cc406Sopenharmony_ci	      port = 0;
806141cc406Sopenharmony_ci	      continue;
807141cc406Sopenharmony_ci	    }
808141cc406Sopenharmony_ci
809141cc406Sopenharmony_ci	  config_line_ptr = sanei_config_skip_whitespace (config_line_ptr);
810141cc406Sopenharmony_ci	  if (!*config_line_ptr)
811141cc406Sopenharmony_ci	    {
812141cc406Sopenharmony_ci	      DBG (1, "sane_init: parse error in line %d after "
813141cc406Sopenharmony_ci		"``scanner %s %s''\n", line, name, port);
814141cc406Sopenharmony_ci	      free (name);
815141cc406Sopenharmony_ci	      free (port);
816141cc406Sopenharmony_ci	      name = 0;
817141cc406Sopenharmony_ci	      port = 0;
818141cc406Sopenharmony_ci	      continue;
819141cc406Sopenharmony_ci	    }
820141cc406Sopenharmony_ci
821141cc406Sopenharmony_ci	  config_line_ptr = sanei_config_get_string (config_line_ptr, &driver);
822141cc406Sopenharmony_ci	  if ((driver == NULL) || (!*driver))
823141cc406Sopenharmony_ci	    {
824141cc406Sopenharmony_ci	      DBG (1, "sane_init: parse error in line %d after "
825141cc406Sopenharmony_ci		"``scanner %s %s''\n", line, name, port);
826141cc406Sopenharmony_ci	      free (name);
827141cc406Sopenharmony_ci	      name = 0;
828141cc406Sopenharmony_ci	      free (port);
829141cc406Sopenharmony_ci	      port = 0;
830141cc406Sopenharmony_ci	      if (driver != NULL)
831141cc406Sopenharmony_ci		free (driver);
832141cc406Sopenharmony_ci	      driver = 0;
833141cc406Sopenharmony_ci	      continue;
834141cc406Sopenharmony_ci	    }
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_ci	  config_line_ptr = sanei_config_skip_whitespace (config_line_ptr);
837141cc406Sopenharmony_ci
838141cc406Sopenharmony_ci	  if (*config_line_ptr)
839141cc406Sopenharmony_ci	    {
840141cc406Sopenharmony_ci	      config_line_ptr = sanei_config_get_string (config_line_ptr,
841141cc406Sopenharmony_ci							&option_ta);
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci	      if ((option_ta == NULL) || (!*option_ta) ||
844141cc406Sopenharmony_ci		  (strcasecmp (option_ta, "use_ta") != 0))
845141cc406Sopenharmony_ci		{
846141cc406Sopenharmony_ci		  DBG (1, "sane_init: parse error in line %d after "
847141cc406Sopenharmony_ci			"``scanner %s %s %s''\n", line, name, port, driver);
848141cc406Sopenharmony_ci		  free (name);
849141cc406Sopenharmony_ci		  free (port);
850141cc406Sopenharmony_ci		  free (driver);
851141cc406Sopenharmony_ci		  if (option_ta)
852141cc406Sopenharmony_ci		    free (option_ta);
853141cc406Sopenharmony_ci		  name = port = driver = option_ta = 0;
854141cc406Sopenharmony_ci		  continue;
855141cc406Sopenharmony_ci		}
856141cc406Sopenharmony_ci	    }
857141cc406Sopenharmony_ci
858141cc406Sopenharmony_ci	  if (*config_line_ptr)
859141cc406Sopenharmony_ci	    {
860141cc406Sopenharmony_ci	      DBG (1, "sane_init: parse error in line %d after "
861141cc406Sopenharmony_ci			"``scanner %s %s %s %s\n", line, name, port, driver,
862141cc406Sopenharmony_ci			(option_ta == 0 ? "" : option_ta));
863141cc406Sopenharmony_ci	      free (name);
864141cc406Sopenharmony_ci	      free (port);
865141cc406Sopenharmony_ci	      free (driver);
866141cc406Sopenharmony_ci	      if (option_ta)
867141cc406Sopenharmony_ci		free (option_ta);
868141cc406Sopenharmony_ci	      name = port = driver = option_ta = 0;
869141cc406Sopenharmony_ci	      continue;
870141cc406Sopenharmony_ci	    }
871141cc406Sopenharmony_ci        }
872141cc406Sopenharmony_ci      else if (strncmp(config_line_ptr, "option", 6) == 0)
873141cc406Sopenharmony_ci        {
874141cc406Sopenharmony_ci          /* Format for options: option <name> [<value>]
875141cc406Sopenharmony_ci             Note that the value is optional. */
876141cc406Sopenharmony_ci          char *optname, *optval = 0;
877141cc406Sopenharmony_ci          Mustek_pp_config_option *tmpoptions;
878141cc406Sopenharmony_ci
879141cc406Sopenharmony_ci          config_line_ptr += 6;
880141cc406Sopenharmony_ci          config_line_ptr = sanei_config_skip_whitespace (config_line_ptr);
881141cc406Sopenharmony_ci          if (!*config_line_ptr)
882141cc406Sopenharmony_ci	    {
883141cc406Sopenharmony_ci	      DBG (1, "sane_init: parse error in line %d after ``option''\n",
884141cc406Sopenharmony_ci	        line);
885141cc406Sopenharmony_ci	      continue;
886141cc406Sopenharmony_ci	    }
887141cc406Sopenharmony_ci
888141cc406Sopenharmony_ci          config_line_ptr = sanei_config_get_string (config_line_ptr, &optname);
889141cc406Sopenharmony_ci          if ((optname == NULL) || (!*optname))
890141cc406Sopenharmony_ci	    {
891141cc406Sopenharmony_ci	      DBG (1, "sane_init: parse error in line %d after ``option''\n",
892141cc406Sopenharmony_ci	        line);
893141cc406Sopenharmony_ci	      if (optname != NULL)
894141cc406Sopenharmony_ci	        free (optname);
895141cc406Sopenharmony_ci	      continue;
896141cc406Sopenharmony_ci	    }
897141cc406Sopenharmony_ci
898141cc406Sopenharmony_ci          config_line_ptr = sanei_config_skip_whitespace (config_line_ptr);
899141cc406Sopenharmony_ci          if (*config_line_ptr)
900141cc406Sopenharmony_ci	    {
901141cc406Sopenharmony_ci              /* The option has a value.
902141cc406Sopenharmony_ci                 No need to check the value; that's up to the backend */
903141cc406Sopenharmony_ci	      config_line_ptr = sanei_config_get_string (config_line_ptr,
904141cc406Sopenharmony_ci                                                         &optval);
905141cc406Sopenharmony_ci
906141cc406Sopenharmony_ci   	      config_line_ptr = sanei_config_skip_whitespace (config_line_ptr);
907141cc406Sopenharmony_ci	    }
908141cc406Sopenharmony_ci
909141cc406Sopenharmony_ci          if (*config_line_ptr)
910141cc406Sopenharmony_ci	    {
911141cc406Sopenharmony_ci	      DBG (1, "sane_init: parse error in line %d after "
912141cc406Sopenharmony_ci		        "``option %s %s''\n", line, optname,
913141cc406Sopenharmony_ci		        (optval == 0 ? "" : optval));
914141cc406Sopenharmony_ci	      free (optname);
915141cc406Sopenharmony_ci	      if (optval)
916141cc406Sopenharmony_ci                 free (optval);
917141cc406Sopenharmony_ci	      continue;
918141cc406Sopenharmony_ci	    }
919141cc406Sopenharmony_ci
920141cc406Sopenharmony_ci	  if (!strcmp (optname, "no_epp"))
921141cc406Sopenharmony_ci	    {
922141cc406Sopenharmony_ci	      u_int pa4s2_options;
923141cc406Sopenharmony_ci	      if (name)
924141cc406Sopenharmony_ci		DBG (2, "sane_init: global option found in local scope, "
925141cc406Sopenharmony_ci			"executing anyway\n");
926141cc406Sopenharmony_ci	      free (optname);
927141cc406Sopenharmony_ci	      if (optval)
928141cc406Sopenharmony_ci	        {
929141cc406Sopenharmony_ci	          DBG (1, "sane_init: unexpected value for option no_epp\n");
930141cc406Sopenharmony_ci	          free (optval);
931141cc406Sopenharmony_ci	          continue;
932141cc406Sopenharmony_ci	        }
933141cc406Sopenharmony_ci	      DBG (3, "sane_init: disabling mode EPP\n");
934141cc406Sopenharmony_ci	      sanei_pa4s2_options (&pa4s2_options, SANE_FALSE);
935141cc406Sopenharmony_ci	      pa4s2_options |= SANEI_PA4S2_OPT_NO_EPP;
936141cc406Sopenharmony_ci	      sanei_pa4s2_options (&pa4s2_options, SANE_TRUE);
937141cc406Sopenharmony_ci	      continue;
938141cc406Sopenharmony_ci	    }
939141cc406Sopenharmony_ci	  else if (!name)
940141cc406Sopenharmony_ci	    {
941141cc406Sopenharmony_ci	      DBG (1, "sane_init: parse error in line %d: unexpected "
942141cc406Sopenharmony_ci                      " ``option''\n", line);
943141cc406Sopenharmony_ci	      free (optname);
944141cc406Sopenharmony_ci	      if (optval)
945141cc406Sopenharmony_ci                 free (optval);
946141cc406Sopenharmony_ci	      continue;
947141cc406Sopenharmony_ci	    }
948141cc406Sopenharmony_ci
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_ci          /* Extend the (global) array of options */
951141cc406Sopenharmony_ci          tmpoptions = realloc(cfgoptions,
952141cc406Sopenharmony_ci                               (numcfgoptions+1)*sizeof(cfgoptions[0]));
953141cc406Sopenharmony_ci          if (!tmpoptions)
954141cc406Sopenharmony_ci          {
955141cc406Sopenharmony_ci             DBG (1, "sane_init: not enough memory for device options\n");
956141cc406Sopenharmony_ci             free_cfg_options(&numcfgoptions, &cfgoptions);
957141cc406Sopenharmony_ci             return SANE_STATUS_NO_MEM;
958141cc406Sopenharmony_ci          }
959141cc406Sopenharmony_ci
960141cc406Sopenharmony_ci          cfgoptions = tmpoptions;
961141cc406Sopenharmony_ci          cfgoptions[numcfgoptions].name = optname;
962141cc406Sopenharmony_ci          cfgoptions[numcfgoptions].value = optval;
963141cc406Sopenharmony_ci          ++numcfgoptions;
964141cc406Sopenharmony_ci        }
965141cc406Sopenharmony_ci      else
966141cc406Sopenharmony_ci	{
967141cc406Sopenharmony_ci	  DBG (1, "sane_init: parse error at beginning of line %d\n", line);
968141cc406Sopenharmony_ci	  continue;
969141cc406Sopenharmony_ci	}
970141cc406Sopenharmony_ci
971141cc406Sopenharmony_ci    }
972141cc406Sopenharmony_ci
973141cc406Sopenharmony_ci  /* If we hit the end of the file, we still may have to process the
974141cc406Sopenharmony_ci     last driver */
975141cc406Sopenharmony_ci  if (name)
976141cc406Sopenharmony_ci     attach_device(&driver, &name, &port, &option_ta);
977141cc406Sopenharmony_ci
978141cc406Sopenharmony_ci  fclose(fp);
979141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
980141cc406Sopenharmony_ci
981141cc406Sopenharmony_ci}
982141cc406Sopenharmony_ci
983141cc406Sopenharmony_ci/* sane_exit:
984141cc406Sopenharmony_ci *	Unloads all drivers and frees allocated memory
985141cc406Sopenharmony_ci *
986141cc406Sopenharmony_ci * Description:
987141cc406Sopenharmony_ci * 	All open devices are closed first. Then all registered devices
988141cc406Sopenharmony_ci * 	are removed.
989141cc406Sopenharmony_ci *
990141cc406Sopenharmony_ci */
991141cc406Sopenharmony_ci
992141cc406Sopenharmony_civoid
993141cc406Sopenharmony_cisane_exit (void)
994141cc406Sopenharmony_ci{
995141cc406Sopenharmony_ci  Mustek_pp_Handle *hndl;
996141cc406Sopenharmony_ci  Mustek_pp_Device *dev;
997141cc406Sopenharmony_ci
998141cc406Sopenharmony_ci  if (first_hndl)
999141cc406Sopenharmony_ci    DBG (3, "sane_exit: closing open devices\n");
1000141cc406Sopenharmony_ci
1001141cc406Sopenharmony_ci  while (first_hndl)
1002141cc406Sopenharmony_ci    {
1003141cc406Sopenharmony_ci      hndl = first_hndl;
1004141cc406Sopenharmony_ci      sane_close (hndl);
1005141cc406Sopenharmony_ci    }
1006141cc406Sopenharmony_ci
1007141cc406Sopenharmony_ci  dev = devlist;
1008141cc406Sopenharmony_ci  num_devices = 0;
1009141cc406Sopenharmony_ci  devlist = NULL;
1010141cc406Sopenharmony_ci
1011141cc406Sopenharmony_ci  while (dev) {
1012141cc406Sopenharmony_ci
1013141cc406Sopenharmony_ci	  free (dev->port);
1014141cc406Sopenharmony_ci	  free (dev->name);
1015141cc406Sopenharmony_ci	  free (dev->vendor);
1016141cc406Sopenharmony_ci	  free (dev->model);
1017141cc406Sopenharmony_ci	  free (dev->type);
1018141cc406Sopenharmony_ci          free_cfg_options (&dev->numcfgoptions, &dev->cfgoptions);
1019141cc406Sopenharmony_ci	  dev = dev->next;
1020141cc406Sopenharmony_ci
1021141cc406Sopenharmony_ci  }
1022141cc406Sopenharmony_ci
1023141cc406Sopenharmony_ci  if (devarray != NULL)
1024141cc406Sopenharmony_ci    free (devarray);
1025141cc406Sopenharmony_ci  devarray = NULL;
1026141cc406Sopenharmony_ci
1027141cc406Sopenharmony_ci  DBG (3, "sane_exit: all drivers unloaded\n");
1028141cc406Sopenharmony_ci
1029141cc406Sopenharmony_ci}
1030141cc406Sopenharmony_ci
1031141cc406Sopenharmony_ci/* sane_get_devices:
1032141cc406Sopenharmony_ci * 	Returns a list of registered devices
1033141cc406Sopenharmony_ci *
1034141cc406Sopenharmony_ci * Description:
1035141cc406Sopenharmony_ci * 	A possible present old device_list is removed first. A new
1036141cc406Sopenharmony_ci * 	devarray is allocated and filled with pointers to the
1037141cc406Sopenharmony_ci * 	SANE_Device structures of the Mustek_pp_Devices
1038141cc406Sopenharmony_ci */
1039141cc406Sopenharmony_ci/*ARGSUSED*/
1040141cc406Sopenharmony_ciSANE_Status
1041141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list,
1042141cc406Sopenharmony_ci		  SANE_Bool local_only __UNUSED__)
1043141cc406Sopenharmony_ci{
1044141cc406Sopenharmony_ci  int ctr;
1045141cc406Sopenharmony_ci  Mustek_pp_Device *dev;
1046141cc406Sopenharmony_ci
1047141cc406Sopenharmony_ci  if (devarray != NULL)
1048141cc406Sopenharmony_ci    free (devarray);
1049141cc406Sopenharmony_ci
1050141cc406Sopenharmony_ci  devarray = malloc ((num_devices + 1) * sizeof (devarray[0]));
1051141cc406Sopenharmony_ci
1052141cc406Sopenharmony_ci  if (devarray == NULL)
1053141cc406Sopenharmony_ci    {
1054141cc406Sopenharmony_ci      DBG (1, "sane_get_devices: not enough memory for device list\n");
1055141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1056141cc406Sopenharmony_ci    }
1057141cc406Sopenharmony_ci
1058141cc406Sopenharmony_ci  dev = devlist;
1059141cc406Sopenharmony_ci
1060141cc406Sopenharmony_ci  for (ctr=0 ; ctr<num_devices ; ctr++) {
1061141cc406Sopenharmony_ci	  devarray[ctr] = &dev->sane;
1062141cc406Sopenharmony_ci	  dev = dev->next;
1063141cc406Sopenharmony_ci  }
1064141cc406Sopenharmony_ci
1065141cc406Sopenharmony_ci  devarray[num_devices] = NULL;
1066141cc406Sopenharmony_ci  *device_list = (const SANE_Device **)devarray;
1067141cc406Sopenharmony_ci
1068141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1069141cc406Sopenharmony_ci}
1070141cc406Sopenharmony_ci
1071141cc406Sopenharmony_ci/* sane_open:
1072141cc406Sopenharmony_ci * 	opens a device and prepares it for operation
1073141cc406Sopenharmony_ci *
1074141cc406Sopenharmony_ci * Description:
1075141cc406Sopenharmony_ci * 	The device identified by ``devicename'' is looked
1076141cc406Sopenharmony_ci * 	up in the list, or if devicename is zero, the
1077141cc406Sopenharmony_ci * 	first device from the list is taken.
1078141cc406Sopenharmony_ci *
1079141cc406Sopenharmony_ci * 	open is called for the selected device.
1080141cc406Sopenharmony_ci *
1081141cc406Sopenharmony_ci * 	The handle is set up with default values, and the
1082141cc406Sopenharmony_ci * 	option descriptors are initialized
1083141cc406Sopenharmony_ci */
1084141cc406Sopenharmony_ci
1085141cc406Sopenharmony_ciSANE_Status
1086141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
1087141cc406Sopenharmony_ci{
1088141cc406Sopenharmony_ci
1089141cc406Sopenharmony_ci	Mustek_pp_Handle *hndl;
1090141cc406Sopenharmony_ci	Mustek_pp_Device *dev;
1091141cc406Sopenharmony_ci	SANE_Status status;
1092141cc406Sopenharmony_ci	int	fd, i;
1093141cc406Sopenharmony_ci
1094141cc406Sopenharmony_ci	if (devicename[0]) {
1095141cc406Sopenharmony_ci
1096141cc406Sopenharmony_ci		dev = devlist;
1097141cc406Sopenharmony_ci
1098141cc406Sopenharmony_ci		while (dev) {
1099141cc406Sopenharmony_ci
1100141cc406Sopenharmony_ci			if (strcmp (dev->name, devicename) == 0)
1101141cc406Sopenharmony_ci				break;
1102141cc406Sopenharmony_ci
1103141cc406Sopenharmony_ci			dev = dev->next;
1104141cc406Sopenharmony_ci
1105141cc406Sopenharmony_ci		}
1106141cc406Sopenharmony_ci
1107141cc406Sopenharmony_ci		if (!dev) {
1108141cc406Sopenharmony_ci
1109141cc406Sopenharmony_ci			DBG (1, "sane_open: unknown devicename ``%s''\n", devicename);
1110141cc406Sopenharmony_ci			return SANE_STATUS_INVAL;
1111141cc406Sopenharmony_ci
1112141cc406Sopenharmony_ci		}
1113141cc406Sopenharmony_ci	} else
1114141cc406Sopenharmony_ci		dev = devlist;
1115141cc406Sopenharmony_ci
1116141cc406Sopenharmony_ci	if (!dev) {
1117141cc406Sopenharmony_ci		DBG (1, "sane_open: no devices present...\n");
1118141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
1119141cc406Sopenharmony_ci	}
1120141cc406Sopenharmony_ci
1121141cc406Sopenharmony_ci	DBG (3, "sane_open: Using device ``%s'' (driver %s v%s by %s)\n",
1122141cc406Sopenharmony_ci			dev->name, dev->func->driver, dev->func->version, dev->func->author);
1123141cc406Sopenharmony_ci
1124141cc406Sopenharmony_ci	if ((hndl = malloc (sizeof (Mustek_pp_Handle))) == NULL) {
1125141cc406Sopenharmony_ci
1126141cc406Sopenharmony_ci		DBG (1, "sane_open: not enough free memory for the handle\n");
1127141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
1128141cc406Sopenharmony_ci
1129141cc406Sopenharmony_ci	}
1130141cc406Sopenharmony_ci
1131141cc406Sopenharmony_ci	if ((status = dev->func->open (dev->port, dev->caps, &fd)) != SANE_STATUS_GOOD) {
1132141cc406Sopenharmony_ci
1133141cc406Sopenharmony_ci		DBG (1, "sane_open: could not open device (%s)\n",
1134141cc406Sopenharmony_ci				sane_strstatus (status));
1135141cc406Sopenharmony_ci		return status;
1136141cc406Sopenharmony_ci
1137141cc406Sopenharmony_ci	}
1138141cc406Sopenharmony_ci
1139141cc406Sopenharmony_ci	hndl->next = first_hndl;
1140141cc406Sopenharmony_ci	hndl->dev = dev;
1141141cc406Sopenharmony_ci	hndl->fd = fd;
1142141cc406Sopenharmony_ci	hndl->state = STATE_IDLE;
1143141cc406Sopenharmony_ci	hndl->pipe = -1;
1144141cc406Sopenharmony_ci
1145141cc406Sopenharmony_ci	init_options (hndl);
1146141cc406Sopenharmony_ci
1147141cc406Sopenharmony_ci	dev->func->setup (hndl);
1148141cc406Sopenharmony_ci
1149141cc406Sopenharmony_ci        /* Initialize driver-specific configuration options. This must be
1150141cc406Sopenharmony_ci           done after calling the setup() function because only then the
1151141cc406Sopenharmony_ci           driver is guaranteed to be fully initialized */
1152141cc406Sopenharmony_ci        for (i = 0; i<dev->numcfgoptions; ++i)
1153141cc406Sopenharmony_ci        {
1154141cc406Sopenharmony_ci           status = dev->func->config (hndl,
1155141cc406Sopenharmony_ci		  		       dev->cfgoptions[i].name,
1156141cc406Sopenharmony_ci				       dev->cfgoptions[i].value);
1157141cc406Sopenharmony_ci           if (status != SANE_STATUS_GOOD)
1158141cc406Sopenharmony_ci           {
1159141cc406Sopenharmony_ci              DBG (1, "sane_open: could not set option %s for device (%s)\n",
1160141cc406Sopenharmony_ci            		dev->cfgoptions[i].name, sane_strstatus (status));
1161141cc406Sopenharmony_ci
1162141cc406Sopenharmony_ci              /* Question: should the initialization be aborted when an
1163141cc406Sopenharmony_ci                 option cannot be handled ?
1164141cc406Sopenharmony_ci                 The driver should have reasonable built-in defaults, so
1165141cc406Sopenharmony_ci                 an illegal option value or an unknown option should not
1166141cc406Sopenharmony_ci                 be fatal. Therefore, it's probably ok to ignore the error. */
1167141cc406Sopenharmony_ci           }
1168141cc406Sopenharmony_ci        }
1169141cc406Sopenharmony_ci
1170141cc406Sopenharmony_ci	first_hndl = hndl;
1171141cc406Sopenharmony_ci
1172141cc406Sopenharmony_ci	*handle = hndl;
1173141cc406Sopenharmony_ci
1174141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1175141cc406Sopenharmony_ci}
1176141cc406Sopenharmony_ci
1177141cc406Sopenharmony_ci/* sane_close:
1178141cc406Sopenharmony_ci * 	closes a given device and frees all resources
1179141cc406Sopenharmony_ci *
1180141cc406Sopenharmony_ci * Description:
1181141cc406Sopenharmony_ci * 	The handle is searched in the list of active handles.
1182141cc406Sopenharmony_ci * 	If it's found, the handle is removed.
1183141cc406Sopenharmony_ci *
1184141cc406Sopenharmony_ci * 	If the associated device is still scanning, the process
1185141cc406Sopenharmony_ci * 	is cancelled.
1186141cc406Sopenharmony_ci *
1187141cc406Sopenharmony_ci * 	Then the backend makes sure, the lamp was at least
1188141cc406Sopenharmony_ci * 	2 seconds on.
1189141cc406Sopenharmony_ci *
1190141cc406Sopenharmony_ci * 	Afterwards the selected handle is closed
1191141cc406Sopenharmony_ci */
1192141cc406Sopenharmony_civoid
1193141cc406Sopenharmony_cisane_close (SANE_Handle handle)
1194141cc406Sopenharmony_ci{
1195141cc406Sopenharmony_ci  Mustek_pp_Handle *prev, *hndl;
1196141cc406Sopenharmony_ci
1197141cc406Sopenharmony_ci  prev = NULL;
1198141cc406Sopenharmony_ci
1199141cc406Sopenharmony_ci  for (hndl = first_hndl; hndl; hndl = hndl->next)
1200141cc406Sopenharmony_ci    {
1201141cc406Sopenharmony_ci      if (hndl == handle)
1202141cc406Sopenharmony_ci	break;
1203141cc406Sopenharmony_ci      prev = hndl;
1204141cc406Sopenharmony_ci    }
1205141cc406Sopenharmony_ci
1206141cc406Sopenharmony_ci  if (hndl == NULL)
1207141cc406Sopenharmony_ci    {
1208141cc406Sopenharmony_ci      DBG (2, "sane_close: unknown device handle\n");
1209141cc406Sopenharmony_ci      return;
1210141cc406Sopenharmony_ci    }
1211141cc406Sopenharmony_ci
1212141cc406Sopenharmony_ci  if (hndl->state == STATE_SCANNING) {
1213141cc406Sopenharmony_ci    sane_cancel (handle);
1214141cc406Sopenharmony_ci    do_eof (handle);
1215141cc406Sopenharmony_ci  }
1216141cc406Sopenharmony_ci
1217141cc406Sopenharmony_ci  if (prev != NULL)
1218141cc406Sopenharmony_ci    prev->next = hndl->next;
1219141cc406Sopenharmony_ci  else
1220141cc406Sopenharmony_ci    first_hndl = hndl->next;
1221141cc406Sopenharmony_ci
1222141cc406Sopenharmony_ci  DBG (3, "sane_close: maybe waiting for lamp...\n");
1223141cc406Sopenharmony_ci  if (hndl->lamp_on)
1224141cc406Sopenharmony_ci    while (time (NULL) - hndl->lamp_on < 2)
1225141cc406Sopenharmony_ci      sleep (1);
1226141cc406Sopenharmony_ci
1227141cc406Sopenharmony_ci  hndl->dev->func->close (hndl);
1228141cc406Sopenharmony_ci
1229141cc406Sopenharmony_ci  DBG (3, "sane_close: device closed\n");
1230141cc406Sopenharmony_ci
1231141cc406Sopenharmony_ci  free (handle);
1232141cc406Sopenharmony_ci
1233141cc406Sopenharmony_ci}
1234141cc406Sopenharmony_ci
1235141cc406Sopenharmony_ci/* sane_get_option_descriptor:
1236141cc406Sopenharmony_ci * 	does what it says
1237141cc406Sopenharmony_ci *
1238141cc406Sopenharmony_ci * Description:
1239141cc406Sopenharmony_ci *
1240141cc406Sopenharmony_ci */
1241141cc406Sopenharmony_ci
1242141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
1243141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
1244141cc406Sopenharmony_ci{
1245141cc406Sopenharmony_ci  Mustek_pp_Handle *hndl = handle;
1246141cc406Sopenharmony_ci
1247141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
1248141cc406Sopenharmony_ci    {
1249141cc406Sopenharmony_ci      DBG (2, "sane_get_option_descriptor: option %d doesn't exist\n", option);
1250141cc406Sopenharmony_ci      return NULL;
1251141cc406Sopenharmony_ci    }
1252141cc406Sopenharmony_ci
1253141cc406Sopenharmony_ci  return hndl->opt + option;
1254141cc406Sopenharmony_ci}
1255141cc406Sopenharmony_ci
1256141cc406Sopenharmony_ci
1257141cc406Sopenharmony_ci/* sane_control_option:
1258141cc406Sopenharmony_ci * 	Reads or writes an option
1259141cc406Sopenharmony_ci *
1260141cc406Sopenharmony_ci * Description:
1261141cc406Sopenharmony_ci * 	If a pointer to info is given, the value is initialized to zero
1262141cc406Sopenharmony_ci *	while scanning options cannot be read or written. next a basic
1263141cc406Sopenharmony_ci *	check whether the request is valid is done.
1264141cc406Sopenharmony_ci *
1265141cc406Sopenharmony_ci *	Depending on ``action'' the value of the option is either read
1266141cc406Sopenharmony_ci *	(in the first block) or written (in the second block). auto
1267141cc406Sopenharmony_ci *	values aren't supported.
1268141cc406Sopenharmony_ci *
1269141cc406Sopenharmony_ci *	before a value is written, some checks are performed. Depending
1270141cc406Sopenharmony_ci *	on the option, that is written, other options also change
1271141cc406Sopenharmony_ci *
1272141cc406Sopenharmony_ci */
1273141cc406Sopenharmony_ciSANE_Status
1274141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
1275141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
1276141cc406Sopenharmony_ci{
1277141cc406Sopenharmony_ci  Mustek_pp_Handle *hndl = handle;
1278141cc406Sopenharmony_ci  SANE_Status status;
1279141cc406Sopenharmony_ci  SANE_Word w, cap;
1280141cc406Sopenharmony_ci
1281141cc406Sopenharmony_ci  if (info)
1282141cc406Sopenharmony_ci    *info = 0;
1283141cc406Sopenharmony_ci
1284141cc406Sopenharmony_ci  if (hndl->state == STATE_SCANNING)
1285141cc406Sopenharmony_ci    {
1286141cc406Sopenharmony_ci      DBG (2, "sane_control_option: device is scanning\n");
1287141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
1288141cc406Sopenharmony_ci    }
1289141cc406Sopenharmony_ci
1290141cc406Sopenharmony_ci  if ((unsigned int) option >= NUM_OPTIONS)
1291141cc406Sopenharmony_ci    {
1292141cc406Sopenharmony_ci      DBG (2, "sane_control_option: option %d doesn't exist\n", option);
1293141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1294141cc406Sopenharmony_ci    }
1295141cc406Sopenharmony_ci
1296141cc406Sopenharmony_ci  cap = hndl->opt[option].cap;
1297141cc406Sopenharmony_ci
1298141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
1299141cc406Sopenharmony_ci    {
1300141cc406Sopenharmony_ci      DBG (2, "sane_control_option: option %d isn't active\n", option);
1301141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1302141cc406Sopenharmony_ci    }
1303141cc406Sopenharmony_ci
1304141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
1305141cc406Sopenharmony_ci    {
1306141cc406Sopenharmony_ci
1307141cc406Sopenharmony_ci      switch (option)
1308141cc406Sopenharmony_ci	{
1309141cc406Sopenharmony_ci	  /* word options: */
1310141cc406Sopenharmony_ci	case OPT_PREVIEW:
1311141cc406Sopenharmony_ci	case OPT_GRAY_PREVIEW:
1312141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1313141cc406Sopenharmony_ci	case OPT_TL_X:
1314141cc406Sopenharmony_ci	case OPT_TL_Y:
1315141cc406Sopenharmony_ci	case OPT_BR_X:
1316141cc406Sopenharmony_ci	case OPT_BR_Y:
1317141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
1318141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
1319141cc406Sopenharmony_ci	case OPT_INVERT:
1320141cc406Sopenharmony_ci	case OPT_DEPTH:
1321141cc406Sopenharmony_ci
1322141cc406Sopenharmony_ci	  *(SANE_Word *) val = hndl->val[option].w;
1323141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1324141cc406Sopenharmony_ci
1325141cc406Sopenharmony_ci	  /* word-array options: */
1326141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
1327141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
1328141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
1329141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
1330141cc406Sopenharmony_ci
1331141cc406Sopenharmony_ci	  memcpy (val, hndl->val[option].wa, hndl->opt[option].size);
1332141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1333141cc406Sopenharmony_ci
1334141cc406Sopenharmony_ci	  /* string options: */
1335141cc406Sopenharmony_ci	case OPT_MODE:
1336141cc406Sopenharmony_ci	case OPT_SPEED:
1337141cc406Sopenharmony_ci
1338141cc406Sopenharmony_ci	  strcpy (val, hndl->val[option].s);
1339141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1340141cc406Sopenharmony_ci	}
1341141cc406Sopenharmony_ci    }
1342141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
1343141cc406Sopenharmony_ci    {
1344141cc406Sopenharmony_ci
1345141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
1346141cc406Sopenharmony_ci	{
1347141cc406Sopenharmony_ci	  DBG (2, "sane_control_option: option can't be set (%s)\n",
1348141cc406Sopenharmony_ci			  hndl->opt[option].name);
1349141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1350141cc406Sopenharmony_ci	}
1351141cc406Sopenharmony_ci
1352141cc406Sopenharmony_ci      status = sanei_constrain_value (hndl->opt + option, val, info);
1353141cc406Sopenharmony_ci
1354141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
1355141cc406Sopenharmony_ci	{
1356141cc406Sopenharmony_ci	  DBG (2, "sane_control_option: constrain_value failed (%s)\n",
1357141cc406Sopenharmony_ci	       sane_strstatus (status));
1358141cc406Sopenharmony_ci	  return status;
1359141cc406Sopenharmony_ci	}
1360141cc406Sopenharmony_ci
1361141cc406Sopenharmony_ci      switch (option)
1362141cc406Sopenharmony_ci	{
1363141cc406Sopenharmony_ci	  /* (mostly) side-effect-free word options: */
1364141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1365141cc406Sopenharmony_ci	case OPT_TL_X:
1366141cc406Sopenharmony_ci	case OPT_BR_X:
1367141cc406Sopenharmony_ci	case OPT_TL_Y:
1368141cc406Sopenharmony_ci	case OPT_BR_Y:
1369141cc406Sopenharmony_ci	case OPT_PREVIEW:
1370141cc406Sopenharmony_ci	case OPT_GRAY_PREVIEW:
1371141cc406Sopenharmony_ci	case OPT_INVERT:
1372141cc406Sopenharmony_ci	case OPT_DEPTH:
1373141cc406Sopenharmony_ci
1374141cc406Sopenharmony_ci	  if (info)
1375141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_PARAMS;
1376141cc406Sopenharmony_ci
1377141cc406Sopenharmony_ci	  hndl->val[option].w = *(SANE_Word *) val;
1378141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1379141cc406Sopenharmony_ci
1380141cc406Sopenharmony_ci	  /* side-effect-free word-array options: */
1381141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
1382141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
1383141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
1384141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
1385141cc406Sopenharmony_ci
1386141cc406Sopenharmony_ci	  memcpy (hndl->val[option].wa, val, hndl->opt[option].size);
1387141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1388141cc406Sopenharmony_ci
1389141cc406Sopenharmony_ci	  /* side-effect-free string options: */
1390141cc406Sopenharmony_ci	case OPT_SPEED:
1391141cc406Sopenharmony_ci
1392141cc406Sopenharmony_ci	  if (hndl->val[option].s)
1393141cc406Sopenharmony_ci		  free (hndl->val[option].s);
1394141cc406Sopenharmony_ci
1395141cc406Sopenharmony_ci	  hndl->val[option].s = strdup (val);
1396141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1397141cc406Sopenharmony_ci
1398141cc406Sopenharmony_ci
1399141cc406Sopenharmony_ci	  /* options with side-effects: */
1400141cc406Sopenharmony_ci
1401141cc406Sopenharmony_ci	case OPT_CUSTOM_GAMMA:
1402141cc406Sopenharmony_ci	  w = *(SANE_Word *) val;
1403141cc406Sopenharmony_ci
1404141cc406Sopenharmony_ci	  if (w == hndl->val[OPT_CUSTOM_GAMMA].w)
1405141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;	/* no change */
1406141cc406Sopenharmony_ci
1407141cc406Sopenharmony_ci	  if (info)
1408141cc406Sopenharmony_ci	    *info |= SANE_INFO_RELOAD_OPTIONS;
1409141cc406Sopenharmony_ci
1410141cc406Sopenharmony_ci	  hndl->val[OPT_CUSTOM_GAMMA].w = w;
1411141cc406Sopenharmony_ci
1412141cc406Sopenharmony_ci	  if (w == SANE_TRUE)
1413141cc406Sopenharmony_ci	    {
1414141cc406Sopenharmony_ci	      const char *mode = hndl->val[OPT_MODE].s;
1415141cc406Sopenharmony_ci
1416141cc406Sopenharmony_ci	      if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1417141cc406Sopenharmony_ci		hndl->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1418141cc406Sopenharmony_ci	      else if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1419141cc406Sopenharmony_ci		{
1420141cc406Sopenharmony_ci		  hndl->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1421141cc406Sopenharmony_ci		  hndl->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1422141cc406Sopenharmony_ci		  hndl->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1423141cc406Sopenharmony_ci		  hndl->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1424141cc406Sopenharmony_ci		}
1425141cc406Sopenharmony_ci	    }
1426141cc406Sopenharmony_ci	  else
1427141cc406Sopenharmony_ci	    {
1428141cc406Sopenharmony_ci	      hndl->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1429141cc406Sopenharmony_ci	      hndl->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1430141cc406Sopenharmony_ci	      hndl->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1431141cc406Sopenharmony_ci	      hndl->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1432141cc406Sopenharmony_ci	    }
1433141cc406Sopenharmony_ci
1434141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1435141cc406Sopenharmony_ci
1436141cc406Sopenharmony_ci	case OPT_MODE:
1437141cc406Sopenharmony_ci	  {
1438141cc406Sopenharmony_ci	    char *old_val = hndl->val[option].s;
1439141cc406Sopenharmony_ci
1440141cc406Sopenharmony_ci	    if (old_val)
1441141cc406Sopenharmony_ci	      {
1442141cc406Sopenharmony_ci		if (strcmp (old_val, val) == 0)
1443141cc406Sopenharmony_ci		  return SANE_STATUS_GOOD;	/* no change */
1444141cc406Sopenharmony_ci
1445141cc406Sopenharmony_ci		free (old_val);
1446141cc406Sopenharmony_ci	      }
1447141cc406Sopenharmony_ci
1448141cc406Sopenharmony_ci	    if (info)
1449141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1450141cc406Sopenharmony_ci
1451141cc406Sopenharmony_ci	    hndl->val[option].s = strdup (val);
1452141cc406Sopenharmony_ci
1453141cc406Sopenharmony_ci	    hndl->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1454141cc406Sopenharmony_ci	    hndl->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1455141cc406Sopenharmony_ci	    hndl->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1456141cc406Sopenharmony_ci	    hndl->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1457141cc406Sopenharmony_ci	    hndl->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1458141cc406Sopenharmony_ci
1459141cc406Sopenharmony_ci	    hndl->opt[OPT_DEPTH].cap |= SANE_CAP_INACTIVE;
1460141cc406Sopenharmony_ci
1461141cc406Sopenharmony_ci	    if ((hndl->dev->caps & CAP_DEPTH) && (strcmp(val, SANE_VALUE_SCAN_MODE_COLOR) == 0))
1462141cc406Sopenharmony_ci		    hndl->opt[OPT_DEPTH].cap &= ~SANE_CAP_INACTIVE;
1463141cc406Sopenharmony_ci
1464141cc406Sopenharmony_ci	    if (!(hndl->dev->caps & CAP_GAMMA_CORRECT))
1465141cc406Sopenharmony_ci		    return SANE_STATUS_GOOD;
1466141cc406Sopenharmony_ci
1467141cc406Sopenharmony_ci	    if (strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) != 0)
1468141cc406Sopenharmony_ci	      hndl->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1469141cc406Sopenharmony_ci
1470141cc406Sopenharmony_ci	    if (hndl->val[OPT_CUSTOM_GAMMA].w == SANE_TRUE)
1471141cc406Sopenharmony_ci	      {
1472141cc406Sopenharmony_ci		if (strcmp (val, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1473141cc406Sopenharmony_ci		  hndl->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1474141cc406Sopenharmony_ci		else if (strcmp (val, SANE_VALUE_SCAN_MODE_COLOR) == 0)
1475141cc406Sopenharmony_ci		  {
1476141cc406Sopenharmony_ci		    hndl->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1477141cc406Sopenharmony_ci		    hndl->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1478141cc406Sopenharmony_ci		    hndl->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1479141cc406Sopenharmony_ci		    hndl->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1480141cc406Sopenharmony_ci		  }
1481141cc406Sopenharmony_ci	      }
1482141cc406Sopenharmony_ci
1483141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
1484141cc406Sopenharmony_ci	  }
1485141cc406Sopenharmony_ci	}
1486141cc406Sopenharmony_ci    }
1487141cc406Sopenharmony_ci
1488141cc406Sopenharmony_ci  DBG (2, "sane_control_option: unknown action\n");
1489141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
1490141cc406Sopenharmony_ci}
1491141cc406Sopenharmony_ci
1492141cc406Sopenharmony_ci
1493141cc406Sopenharmony_ci/* sane_get_parameters:
1494141cc406Sopenharmony_ci * 	returns the set of parameters, that is used for the next scan
1495141cc406Sopenharmony_ci *
1496141cc406Sopenharmony_ci * Description:
1497141cc406Sopenharmony_ci *
1498141cc406Sopenharmony_ci * 	First of all it is impossible to change the parameter set
1499141cc406Sopenharmony_ci * 	while scanning.
1500141cc406Sopenharmony_ci *
1501141cc406Sopenharmony_ci * 	sane_get_parameters not only returns the parameters for
1502141cc406Sopenharmony_ci * 	the next scan, it also sets them, i.e. converts the
1503141cc406Sopenharmony_ci * 	options in actually parameters.
1504141cc406Sopenharmony_ci *
1505141cc406Sopenharmony_ci * 	The following parameters are set:
1506141cc406Sopenharmony_ci *
1507141cc406Sopenharmony_ci * 		scanmode:	according to the option SCANMODE, but
1508141cc406Sopenharmony_ci * 				24bit color, if PREVIEW is selected and
1509141cc406Sopenharmony_ci * 				grayscale if GRAY_PREVIEW is selected
1510141cc406Sopenharmony_ci * 		depth:		the bit depth for color modes (if
1511141cc406Sopenharmony_ci * 				supported) or 24bit by default
1512141cc406Sopenharmony_ci * 				(ignored in bw/grayscale or if not
1513141cc406Sopenharmony_ci * 				supported)
1514141cc406Sopenharmony_ci * 		dpi:		resolution
1515141cc406Sopenharmony_ci * 		invert:		if supported else defaults to false
1516141cc406Sopenharmony_ci * 		gamma:		if supported and selected
1517141cc406Sopenharmony_ci * 		ta:		if supported by the device
1518141cc406Sopenharmony_ci * 		speed:		selected speed (or fastest if not
1519141cc406Sopenharmony_ci * 				supported)
1520141cc406Sopenharmony_ci * 		scanarea:	the scanarea is calculated from the
1521141cc406Sopenharmony_ci * 				selections the user has mode. note
1522141cc406Sopenharmony_ci * 				that the area may slightly differ from
1523141cc406Sopenharmony_ci * 				the scanarea selected due to rounding
1524141cc406Sopenharmony_ci * 				note also, that a scanarea of
1525141cc406Sopenharmony_ci * 				(0,0)-(100,100) will include all pixels
1526141cc406Sopenharmony_ci * 				where 0 <= x < 100 and 0 <= y < 100
1527141cc406Sopenharmony_ci * 	afterwards, all values are copied into the SANE_Parameters
1528141cc406Sopenharmony_ci * 	structure.
1529141cc406Sopenharmony_ci */
1530141cc406Sopenharmony_ciSANE_Status
1531141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
1532141cc406Sopenharmony_ci{
1533141cc406Sopenharmony_ci  Mustek_pp_Handle *hndl = handle;
1534141cc406Sopenharmony_ci  char *mode;
1535141cc406Sopenharmony_ci      int dpi, ctr;
1536141cc406Sopenharmony_ci
1537141cc406Sopenharmony_ci  if (hndl->state != STATE_SCANNING)
1538141cc406Sopenharmony_ci    {
1539141cc406Sopenharmony_ci
1540141cc406Sopenharmony_ci
1541141cc406Sopenharmony_ci      memset (&hndl->params, 0, sizeof (hndl->params));
1542141cc406Sopenharmony_ci
1543141cc406Sopenharmony_ci
1544141cc406Sopenharmony_ci      if ((hndl->dev->caps & CAP_DEPTH) && (hndl->mode == MODE_COLOR))
1545141cc406Sopenharmony_ci	hndl->depth = hndl->val[OPT_DEPTH].w;
1546141cc406Sopenharmony_ci      else
1547141cc406Sopenharmony_ci	hndl->depth = 8;
1548141cc406Sopenharmony_ci
1549141cc406Sopenharmony_ci      dpi = (int) (SANE_UNFIX (hndl->val[OPT_RESOLUTION].w) + 0.5);
1550141cc406Sopenharmony_ci
1551141cc406Sopenharmony_ci      hndl->res = dpi;
1552141cc406Sopenharmony_ci
1553141cc406Sopenharmony_ci      if (hndl->dev->caps & CAP_INVERT)
1554141cc406Sopenharmony_ci	hndl->invert = hndl->val[OPT_INVERT].w;
1555141cc406Sopenharmony_ci      else
1556141cc406Sopenharmony_ci	hndl->invert = SANE_FALSE;
1557141cc406Sopenharmony_ci
1558141cc406Sopenharmony_ci      if (hndl->dev->caps & CAP_TA)
1559141cc406Sopenharmony_ci	hndl->use_ta = SANE_TRUE;
1560141cc406Sopenharmony_ci      else
1561141cc406Sopenharmony_ci	hndl->use_ta = SANE_FALSE;
1562141cc406Sopenharmony_ci
1563141cc406Sopenharmony_ci      if ((hndl->dev->caps & CAP_GAMMA_CORRECT) && (hndl->val[OPT_CUSTOM_GAMMA].w == SANE_TRUE))
1564141cc406Sopenharmony_ci	      hndl->do_gamma = SANE_TRUE;
1565141cc406Sopenharmony_ci      else
1566141cc406Sopenharmony_ci	      hndl->do_gamma = SANE_FALSE;
1567141cc406Sopenharmony_ci
1568141cc406Sopenharmony_ci      if (hndl->dev->caps & CAP_SPEED_SELECT) {
1569141cc406Sopenharmony_ci
1570141cc406Sopenharmony_ci	      for (ctr=SPEED_SLOWEST; ctr<=SPEED_FASTEST; ctr++)
1571141cc406Sopenharmony_ci		      if (strcmp(mustek_pp_speeds[ctr], hndl->val[OPT_SPEED].s) == 0)
1572141cc406Sopenharmony_ci			      hndl->speed = ctr;
1573141cc406Sopenharmony_ci
1574141cc406Sopenharmony_ci
1575141cc406Sopenharmony_ci
1576141cc406Sopenharmony_ci      } else
1577141cc406Sopenharmony_ci	      hndl->speed = SPEED_NORMAL;
1578141cc406Sopenharmony_ci
1579141cc406Sopenharmony_ci      mode = hndl->val[OPT_MODE].s;
1580141cc406Sopenharmony_ci
1581141cc406Sopenharmony_ci      if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0)
1582141cc406Sopenharmony_ci	hndl->mode = MODE_BW;
1583141cc406Sopenharmony_ci      else if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
1584141cc406Sopenharmony_ci	hndl->mode = MODE_GRAYSCALE;
1585141cc406Sopenharmony_ci      else
1586141cc406Sopenharmony_ci	hndl->mode = MODE_COLOR;
1587141cc406Sopenharmony_ci
1588141cc406Sopenharmony_ci      if (hndl->val[OPT_PREVIEW].w == SANE_TRUE)
1589141cc406Sopenharmony_ci	{
1590141cc406Sopenharmony_ci
1591141cc406Sopenharmony_ci			hndl->speed = SPEED_FASTEST;
1592141cc406Sopenharmony_ci			hndl->depth = 8;
1593141cc406Sopenharmony_ci			if (! hndl->use_ta)
1594141cc406Sopenharmony_ci			hndl->invert = SANE_FALSE;
1595141cc406Sopenharmony_ci			hndl->do_gamma = SANE_FALSE;
1596141cc406Sopenharmony_ci
1597141cc406Sopenharmony_ci	  if (hndl->val[OPT_GRAY_PREVIEW].w == SANE_TRUE)
1598141cc406Sopenharmony_ci	    hndl->mode = MODE_GRAYSCALE;
1599141cc406Sopenharmony_ci	  else {
1600141cc406Sopenharmony_ci	    hndl->mode = MODE_COLOR;
1601141cc406Sopenharmony_ci	  }
1602141cc406Sopenharmony_ci
1603141cc406Sopenharmony_ci	}
1604141cc406Sopenharmony_ci
1605141cc406Sopenharmony_ci      hndl->topX =
1606141cc406Sopenharmony_ci	MIN ((int)
1607141cc406Sopenharmony_ci	     (MM_TO_PIXEL (SANE_UNFIX(hndl->val[OPT_TL_X].w), hndl->dev->maxres) +
1608141cc406Sopenharmony_ci	      0.5), hndl->dev->maxhsize);
1609141cc406Sopenharmony_ci      hndl->topY =
1610141cc406Sopenharmony_ci	MIN ((int)
1611141cc406Sopenharmony_ci	     (MM_TO_PIXEL (SANE_UNFIX(hndl->val[OPT_TL_Y].w), hndl->dev->maxres) +
1612141cc406Sopenharmony_ci	      0.5), hndl->dev->maxvsize);
1613141cc406Sopenharmony_ci
1614141cc406Sopenharmony_ci      hndl->bottomX =
1615141cc406Sopenharmony_ci	MIN ((int)
1616141cc406Sopenharmony_ci	     (MM_TO_PIXEL (SANE_UNFIX(hndl->val[OPT_BR_X].w), hndl->dev->maxres) +
1617141cc406Sopenharmony_ci	      0.5), hndl->dev->maxhsize);
1618141cc406Sopenharmony_ci      hndl->bottomY =
1619141cc406Sopenharmony_ci	MIN ((int)
1620141cc406Sopenharmony_ci	     (MM_TO_PIXEL (SANE_UNFIX(hndl->val[OPT_BR_Y].w), hndl->dev->maxres) +
1621141cc406Sopenharmony_ci	      0.5), hndl->dev->maxvsize);
1622141cc406Sopenharmony_ci
1623141cc406Sopenharmony_ci      /* If necessary, swap the upper and lower boundaries to avoid negative
1624141cc406Sopenharmony_ci         distances. */
1625141cc406Sopenharmony_ci      if (hndl->topX > hndl->bottomX) {
1626141cc406Sopenharmony_ci	SANE_Int tmp = hndl->topX;
1627141cc406Sopenharmony_ci	hndl->topX = hndl->bottomX;
1628141cc406Sopenharmony_ci	hndl->bottomX = tmp;
1629141cc406Sopenharmony_ci      }
1630141cc406Sopenharmony_ci      if (hndl->topY > hndl->bottomY) {
1631141cc406Sopenharmony_ci	SANE_Int tmp = hndl->topY;
1632141cc406Sopenharmony_ci	hndl->topY = hndl->bottomY;
1633141cc406Sopenharmony_ci	hndl->bottomY = tmp;
1634141cc406Sopenharmony_ci      }
1635141cc406Sopenharmony_ci
1636141cc406Sopenharmony_ci      hndl->params.pixels_per_line = (hndl->bottomX - hndl->topX) * hndl->res
1637141cc406Sopenharmony_ci	/ hndl->dev->maxres;
1638141cc406Sopenharmony_ci
1639141cc406Sopenharmony_ci      hndl->params.bytes_per_line = hndl->params.pixels_per_line;
1640141cc406Sopenharmony_ci
1641141cc406Sopenharmony_ci      switch (hndl->mode)
1642141cc406Sopenharmony_ci	{
1643141cc406Sopenharmony_ci
1644141cc406Sopenharmony_ci	case MODE_BW:
1645141cc406Sopenharmony_ci	  hndl->params.bytes_per_line /= 8;
1646141cc406Sopenharmony_ci
1647141cc406Sopenharmony_ci	  if ((hndl->params.pixels_per_line % 8) != 0)
1648141cc406Sopenharmony_ci	    hndl->params.bytes_per_line++;
1649141cc406Sopenharmony_ci
1650141cc406Sopenharmony_ci	  hndl->params.depth = 1;
1651141cc406Sopenharmony_ci	  break;
1652141cc406Sopenharmony_ci
1653141cc406Sopenharmony_ci	case MODE_GRAYSCALE:
1654141cc406Sopenharmony_ci	  hndl->params.depth = 8;
1655141cc406Sopenharmony_ci	  hndl->params.format = SANE_FRAME_GRAY;
1656141cc406Sopenharmony_ci	  break;
1657141cc406Sopenharmony_ci
1658141cc406Sopenharmony_ci	case MODE_COLOR:
1659141cc406Sopenharmony_ci	  hndl->params.depth = hndl->depth;
1660141cc406Sopenharmony_ci	  hndl->params.bytes_per_line *= 3;
1661141cc406Sopenharmony_ci	  if (hndl->depth > 8)
1662141cc406Sopenharmony_ci	    hndl->params.bytes_per_line *= 2;
1663141cc406Sopenharmony_ci	  hndl->params.format = SANE_FRAME_RGB;
1664141cc406Sopenharmony_ci	  break;
1665141cc406Sopenharmony_ci
1666141cc406Sopenharmony_ci	}
1667141cc406Sopenharmony_ci
1668141cc406Sopenharmony_ci      hndl->params.last_frame = SANE_TRUE;
1669141cc406Sopenharmony_ci
1670141cc406Sopenharmony_ci      hndl->params.lines = (hndl->bottomY - hndl->topY) * hndl->res /
1671141cc406Sopenharmony_ci	hndl->dev->maxres;
1672141cc406Sopenharmony_ci    }
1673141cc406Sopenharmony_ci  else
1674141cc406Sopenharmony_ci      DBG (2, "sane_get_parameters: can't set parameters while scanning\n");
1675141cc406Sopenharmony_ci
1676141cc406Sopenharmony_ci  if (params != NULL)
1677141cc406Sopenharmony_ci    *params = hndl->params;
1678141cc406Sopenharmony_ci
1679141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1680141cc406Sopenharmony_ci
1681141cc406Sopenharmony_ci}
1682141cc406Sopenharmony_ci
1683141cc406Sopenharmony_ci
1684141cc406Sopenharmony_ci/* sane_start:
1685141cc406Sopenharmony_ci * 	starts the scan. data acquisition will start immediately
1686141cc406Sopenharmony_ci *
1687141cc406Sopenharmony_ci * Description:
1688141cc406Sopenharmony_ci *
1689141cc406Sopenharmony_ci */
1690141cc406Sopenharmony_ciSANE_Status
1691141cc406Sopenharmony_cisane_start (SANE_Handle handle)
1692141cc406Sopenharmony_ci{
1693141cc406Sopenharmony_ci  Mustek_pp_Handle	*hndl = handle;
1694141cc406Sopenharmony_ci  int			pipeline[2];
1695141cc406Sopenharmony_ci
1696141cc406Sopenharmony_ci  if (hndl->state == STATE_SCANNING) {
1697141cc406Sopenharmony_ci	  DBG (2, "sane_start: device is already scanning\n");
1698141cc406Sopenharmony_ci	  return SANE_STATUS_DEVICE_BUSY;
1699141cc406Sopenharmony_ci
1700141cc406Sopenharmony_ci  }
1701141cc406Sopenharmony_ci
1702141cc406Sopenharmony_ci	sane_get_parameters (hndl, NULL);
1703141cc406Sopenharmony_ci
1704141cc406Sopenharmony_ci	if (pipe(pipeline) < 0) {
1705141cc406Sopenharmony_ci		DBG (1, "sane_start: could not initialize pipe (%s)\n",
1706141cc406Sopenharmony_ci				strerror(errno));
1707141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1708141cc406Sopenharmony_ci	}
1709141cc406Sopenharmony_ci
1710141cc406Sopenharmony_ci	hndl->reader = fork();
1711141cc406Sopenharmony_ci
1712141cc406Sopenharmony_ci	if (hndl->reader == 0) {
1713141cc406Sopenharmony_ci
1714141cc406Sopenharmony_ci		sigset_t	ignore_set;
1715141cc406Sopenharmony_ci		struct SIGACTION	act;
1716141cc406Sopenharmony_ci
1717141cc406Sopenharmony_ci		close (pipeline[0]);
1718141cc406Sopenharmony_ci
1719141cc406Sopenharmony_ci		sigfillset (&ignore_set);
1720141cc406Sopenharmony_ci		sigdelset (&ignore_set, SIGTERM);
1721141cc406Sopenharmony_ci		sigprocmask (SIG_SETMASK, &ignore_set, NULL);
1722141cc406Sopenharmony_ci
1723141cc406Sopenharmony_ci		memset (&act, 0, sizeof(act));
1724141cc406Sopenharmony_ci		sigaction (SIGTERM, &act, NULL);
1725141cc406Sopenharmony_ci
1726141cc406Sopenharmony_ci		_exit (reader_process (hndl, pipeline[1]));
1727141cc406Sopenharmony_ci
1728141cc406Sopenharmony_ci	}
1729141cc406Sopenharmony_ci
1730141cc406Sopenharmony_ci	close (pipeline[1]);
1731141cc406Sopenharmony_ci
1732141cc406Sopenharmony_ci	hndl->pipe = pipeline[0];
1733141cc406Sopenharmony_ci
1734141cc406Sopenharmony_ci	hndl->state = STATE_SCANNING;
1735141cc406Sopenharmony_ci
1736141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1737141cc406Sopenharmony_ci
1738141cc406Sopenharmony_ci}
1739141cc406Sopenharmony_ci
1740141cc406Sopenharmony_ci
1741141cc406Sopenharmony_ci/* sane_read:
1742141cc406Sopenharmony_ci * 	receives data from pipeline and passes it to the caller
1743141cc406Sopenharmony_ci *
1744141cc406Sopenharmony_ci * Description:
1745141cc406Sopenharmony_ci * 	ditto
1746141cc406Sopenharmony_ci */
1747141cc406Sopenharmony_ciSANE_Status
1748141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
1749141cc406Sopenharmony_ci	   SANE_Int * len)
1750141cc406Sopenharmony_ci{
1751141cc406Sopenharmony_ci  Mustek_pp_Handle	*hndl = handle;
1752141cc406Sopenharmony_ci  SANE_Int		nread;
1753141cc406Sopenharmony_ci
1754141cc406Sopenharmony_ci
1755141cc406Sopenharmony_ci  if (hndl->state == STATE_CANCELLED) {
1756141cc406Sopenharmony_ci	  DBG (2, "sane_read: device already cancelled\n");
1757141cc406Sopenharmony_ci	  do_eof (hndl);
1758141cc406Sopenharmony_ci	  hndl->state = STATE_IDLE;
1759141cc406Sopenharmony_ci	  return SANE_STATUS_CANCELLED;
1760141cc406Sopenharmony_ci  }
1761141cc406Sopenharmony_ci
1762141cc406Sopenharmony_ci  if (hndl->state != STATE_SCANNING) {
1763141cc406Sopenharmony_ci	  DBG (1, "sane_read: device isn't scanning\n");
1764141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
1765141cc406Sopenharmony_ci  }
1766141cc406Sopenharmony_ci
1767141cc406Sopenharmony_ci
1768141cc406Sopenharmony_ci  *len = nread = 0;
1769141cc406Sopenharmony_ci
1770141cc406Sopenharmony_ci  while (*len < max_len) {
1771141cc406Sopenharmony_ci
1772141cc406Sopenharmony_ci	  nread = read(hndl->pipe, buf + *len, max_len - *len);
1773141cc406Sopenharmony_ci
1774141cc406Sopenharmony_ci	  if (hndl->state == STATE_CANCELLED) {
1775141cc406Sopenharmony_ci
1776141cc406Sopenharmony_ci		  *len = 0;
1777141cc406Sopenharmony_ci		  DBG(3, "sane_read: scan was cancelled\n");
1778141cc406Sopenharmony_ci
1779141cc406Sopenharmony_ci		  do_eof (hndl);
1780141cc406Sopenharmony_ci		  hndl->state = STATE_IDLE;
1781141cc406Sopenharmony_ci		  return SANE_STATUS_CANCELLED;
1782141cc406Sopenharmony_ci
1783141cc406Sopenharmony_ci	  }
1784141cc406Sopenharmony_ci
1785141cc406Sopenharmony_ci	  if (nread < 0) {
1786141cc406Sopenharmony_ci
1787141cc406Sopenharmony_ci		  if (errno == EAGAIN) {
1788141cc406Sopenharmony_ci
1789141cc406Sopenharmony_ci			  if (*len == 0)
1790141cc406Sopenharmony_ci				  DBG(3, "sane_read: no data at the moment\n");
1791141cc406Sopenharmony_ci			  else
1792141cc406Sopenharmony_ci				  DBG(3, "sane_read: %d bytes read\n", *len);
1793141cc406Sopenharmony_ci
1794141cc406Sopenharmony_ci			  return SANE_STATUS_GOOD;
1795141cc406Sopenharmony_ci
1796141cc406Sopenharmony_ci		  } else {
1797141cc406Sopenharmony_ci
1798141cc406Sopenharmony_ci			  DBG(1, "sane_read: IO error (%s)\n", strerror(errno));
1799141cc406Sopenharmony_ci
1800141cc406Sopenharmony_ci			  hndl->state = STATE_IDLE;
1801141cc406Sopenharmony_ci			  do_stop(hndl);
1802141cc406Sopenharmony_ci
1803141cc406Sopenharmony_ci			  do_eof (hndl);
1804141cc406Sopenharmony_ci
1805141cc406Sopenharmony_ci			  *len = 0;
1806141cc406Sopenharmony_ci			  return SANE_STATUS_IO_ERROR;
1807141cc406Sopenharmony_ci
1808141cc406Sopenharmony_ci		  }
1809141cc406Sopenharmony_ci	  }
1810141cc406Sopenharmony_ci
1811141cc406Sopenharmony_ci	  *len += nread;
1812141cc406Sopenharmony_ci
1813141cc406Sopenharmony_ci	  if (nread == 0) {
1814141cc406Sopenharmony_ci
1815141cc406Sopenharmony_ci		  if (*len == 0) {
1816141cc406Sopenharmony_ci
1817141cc406Sopenharmony_ci			DBG (3, "sane_read: read finished\n");
1818141cc406Sopenharmony_ci			do_stop(hndl);
1819141cc406Sopenharmony_ci
1820141cc406Sopenharmony_ci			hndl->state = STATE_IDLE;
1821141cc406Sopenharmony_ci
1822141cc406Sopenharmony_ci			return do_eof(hndl);
1823141cc406Sopenharmony_ci
1824141cc406Sopenharmony_ci		  }
1825141cc406Sopenharmony_ci
1826141cc406Sopenharmony_ci		  DBG(3, "sane_read: read last buffer of %d bytes\n",
1827141cc406Sopenharmony_ci				  *len);
1828141cc406Sopenharmony_ci
1829141cc406Sopenharmony_ci		  return SANE_STATUS_GOOD;
1830141cc406Sopenharmony_ci
1831141cc406Sopenharmony_ci	  }
1832141cc406Sopenharmony_ci
1833141cc406Sopenharmony_ci  }
1834141cc406Sopenharmony_ci
1835141cc406Sopenharmony_ci  DBG(3, "sane_read: read full buffer of %d bytes\n", *len);
1836141cc406Sopenharmony_ci
1837141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1838141cc406Sopenharmony_ci}
1839141cc406Sopenharmony_ci
1840141cc406Sopenharmony_ci
1841141cc406Sopenharmony_ci/* sane_cancel:
1842141cc406Sopenharmony_ci * 	stops a scan and ends the reader process
1843141cc406Sopenharmony_ci *
1844141cc406Sopenharmony_ci * Description:
1845141cc406Sopenharmony_ci *
1846141cc406Sopenharmony_ci */
1847141cc406Sopenharmony_civoid
1848141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
1849141cc406Sopenharmony_ci{
1850141cc406Sopenharmony_ci  Mustek_pp_Handle *hndl = handle;
1851141cc406Sopenharmony_ci
1852141cc406Sopenharmony_ci  if (hndl->state != STATE_SCANNING)
1853141cc406Sopenharmony_ci	 return;
1854141cc406Sopenharmony_ci
1855141cc406Sopenharmony_ci  hndl->state = STATE_CANCELLED;
1856141cc406Sopenharmony_ci
1857141cc406Sopenharmony_ci  do_stop (hndl);
1858141cc406Sopenharmony_ci
1859141cc406Sopenharmony_ci}
1860141cc406Sopenharmony_ci
1861141cc406Sopenharmony_ci
1862141cc406Sopenharmony_ci/* sane_set_io_mode:
1863141cc406Sopenharmony_ci * 	toggles between blocking and non-blocking reading
1864141cc406Sopenharmony_ci *
1865141cc406Sopenharmony_ci * Description:
1866141cc406Sopenharmony_ci *
1867141cc406Sopenharmony_ci */
1868141cc406Sopenharmony_ciSANE_Status
1869141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
1870141cc406Sopenharmony_ci{
1871141cc406Sopenharmony_ci
1872141cc406Sopenharmony_ci	Mustek_pp_Handle	*hndl=handle;
1873141cc406Sopenharmony_ci
1874141cc406Sopenharmony_ci	if (hndl->state != STATE_SCANNING)
1875141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
1876141cc406Sopenharmony_ci
1877141cc406Sopenharmony_ci
1878141cc406Sopenharmony_ci	if (fcntl (hndl->pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) {
1879141cc406Sopenharmony_ci
1880141cc406Sopenharmony_ci		DBG(1, "sane_set_io_mode: can't set io mode\n");
1881141cc406Sopenharmony_ci
1882141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1883141cc406Sopenharmony_ci
1884141cc406Sopenharmony_ci	}
1885141cc406Sopenharmony_ci
1886141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1887141cc406Sopenharmony_ci}
1888141cc406Sopenharmony_ci
1889141cc406Sopenharmony_ci
1890141cc406Sopenharmony_ci/* sane_get_select_fd:
1891141cc406Sopenharmony_ci * 	returns the pipeline fd for direct reading
1892141cc406Sopenharmony_ci *
1893141cc406Sopenharmony_ci * Description:
1894141cc406Sopenharmony_ci * 	to allow the frontend to receive the data directly it
1895141cc406Sopenharmony_ci * 	can read from the pipeline itself
1896141cc406Sopenharmony_ci */
1897141cc406Sopenharmony_ciSANE_Status
1898141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
1899141cc406Sopenharmony_ci{
1900141cc406Sopenharmony_ci	Mustek_pp_Handle	*hndl=handle;
1901141cc406Sopenharmony_ci
1902141cc406Sopenharmony_ci	if (hndl->state != STATE_SCANNING)
1903141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
1904141cc406Sopenharmony_ci
1905141cc406Sopenharmony_ci	*fd = hndl->pipe;
1906141cc406Sopenharmony_ci
1907141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1908141cc406Sopenharmony_ci}
1909141cc406Sopenharmony_ci
1910141cc406Sopenharmony_ci/* include drivers */
1911141cc406Sopenharmony_ci#include "mustek_pp_decl.h"
1912141cc406Sopenharmony_ci#include "mustek_pp_null.c"
1913141cc406Sopenharmony_ci#include "mustek_pp_cis.h"
1914141cc406Sopenharmony_ci#include "mustek_pp_cis.c"
1915141cc406Sopenharmony_ci#include "mustek_pp_ccd300.h"
1916141cc406Sopenharmony_ci#include "mustek_pp_ccd300.c"
1917