1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci   Copyright (C) 2001-2002 Matthew C. Duggan and Simon Krix
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   -----
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci   This file is part of the canon_pp backend, supporting Canon FBX30P
42141cc406Sopenharmony_ci   and NX40P scanners
43141cc406Sopenharmony_ci   */
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_ci#ifdef  _AIX
46141cc406Sopenharmony_ci#include  <lalloca.h>		/* MUST come first for AIX! */
47141cc406Sopenharmony_ci#endif
48141cc406Sopenharmony_ci
49141cc406Sopenharmony_ci#define BACKEND_NAME canon_pp
50141cc406Sopenharmony_ci
51141cc406Sopenharmony_ci#define THREE_BITS 0xE0
52141cc406Sopenharmony_ci#define TWO_BITS 0xC0
53141cc406Sopenharmony_ci#define MM_PER_IN 25.4
54141cc406Sopenharmony_ci
55141cc406Sopenharmony_ci#ifndef NOSANE
56141cc406Sopenharmony_ci#include "../include/sane/config.h"
57141cc406Sopenharmony_ci#endif
58141cc406Sopenharmony_ci
59141cc406Sopenharmony_ci#include  <string.h>
60141cc406Sopenharmony_ci#include  <math.h>
61141cc406Sopenharmony_ci#include  <unistd.h>
62141cc406Sopenharmony_ci#include  <sys/stat.h>
63141cc406Sopenharmony_ci#include  <sys/types.h>
64141cc406Sopenharmony_ci#include  <stdlib.h>
65141cc406Sopenharmony_ci#include  <errno.h>
66141cc406Sopenharmony_ci#include  <ieee1284.h>
67141cc406Sopenharmony_ci
68141cc406Sopenharmony_ci#include  "../include/sane/sane.h"
69141cc406Sopenharmony_ci#include  "../include/sane/saneopts.h"
70141cc406Sopenharmony_ci
71141cc406Sopenharmony_ci#include "canon_pp-dev.h"
72141cc406Sopenharmony_ci#include "canon_pp-io.h"
73141cc406Sopenharmony_ci#include "canon_pp.h"
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ci/* #include  "../include/sane/sanei_pio.h" */
76141cc406Sopenharmony_ci#include  "../include/sane/sanei_config.h"
77141cc406Sopenharmony_ci#include  "../include/sane/sanei_backend.h"
78141cc406Sopenharmony_ci/* #include  "../include/sane/sanei_debug.h" */
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_ci/* Prototypes */
82141cc406Sopenharmony_cistatic SANE_Status init_device(struct parport *pp);
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_ci/* create a calibration file and give it initial values */
85141cc406Sopenharmony_cistatic int init_cal(char *file);
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_cistatic SANE_Status fix_weights_file(CANONP_Scanner *cs);
88141cc406Sopenharmony_ci
89141cc406Sopenharmony_cistatic SANE_Status detect_mode(CANONP_Scanner *cs);
90141cc406Sopenharmony_ci
91141cc406Sopenharmony_ci/* Global Variables (ack!) */
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_ci/* The first device in a linked list of devices */
94141cc406Sopenharmony_cistatic CANONP_Scanner *first_dev = NULL;
95141cc406Sopenharmony_ci/* The default scanner to open */
96141cc406Sopenharmony_cistatic char *def_scanner = NULL;
97141cc406Sopenharmony_ci/* The number of devices */
98141cc406Sopenharmony_cistatic int num_devices = 0;
99141cc406Sopenharmony_ci/* ieee1284 parallel ports */
100141cc406Sopenharmony_cistruct parport_list pl;
101141cc406Sopenharmony_ci/* leftover from the last read */
102141cc406Sopenharmony_cistatic SANE_Byte *read_leftover = NULL;
103141cc406Sopenharmony_ci/* leftover from the last read */
104141cc406Sopenharmony_cistatic SANE_Bool force_nibble = SANE_FALSE;
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_ci/* Constants */
107141cc406Sopenharmony_ci
108141cc406Sopenharmony_ci/* Colour Modes */
109141cc406Sopenharmony_cistatic const SANE_String_Const cmodes[] = {
110141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_GRAY,
111141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_COLOR,
112141cc406Sopenharmony_ci	NULL };
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_ci/* bit depths */
115141cc406Sopenharmony_cistatic const SANE_String_Const depths[] = { "8", "12", NULL };
116141cc406Sopenharmony_ci/* resolutions */
117141cc406Sopenharmony_cistatic const SANE_Int res300[] = {3, 75, 150, 300};
118141cc406Sopenharmony_cistatic const SANE_Int res600[] = {4, 75, 150, 300, 600};
119141cc406Sopenharmony_ci
120141cc406Sopenharmony_ci
121141cc406Sopenharmony_ci/*************************************************************************
122141cc406Sopenharmony_ci *
123141cc406Sopenharmony_ci * sane_init()
124141cc406Sopenharmony_ci *
125141cc406Sopenharmony_ci * Initialises data for the list of scanners, stored in canon-p.conf.
126141cc406Sopenharmony_ci *
127141cc406Sopenharmony_ci * Scanners are not sent any commands until sane_open() is called.
128141cc406Sopenharmony_ci *
129141cc406Sopenharmony_ci *************************************************************************/
130141cc406Sopenharmony_ci	SANE_Status
131141cc406Sopenharmony_cisane_init (SANE_Int *vc, SANE_Auth_Callback cb)
132141cc406Sopenharmony_ci{
133141cc406Sopenharmony_ci	SANE_Status status = SANE_STATUS_GOOD;
134141cc406Sopenharmony_ci	int i, tmp;
135141cc406Sopenharmony_ci	int tmp_im = INITMODE_AUTO;
136141cc406Sopenharmony_ci	FILE *fp;
137141cc406Sopenharmony_ci	char line[81]; /* plus 1 for a null */
138141cc406Sopenharmony_ci	char *tmp_wf, *tmp_port;
139141cc406Sopenharmony_ci	CANONP_Scanner *s_tmp;
140141cc406Sopenharmony_ci
141141cc406Sopenharmony_ci
142141cc406Sopenharmony_ci	DBG_INIT();
143141cc406Sopenharmony_ci
144141cc406Sopenharmony_ci#if defined PACKAGE && defined VERSION
145141cc406Sopenharmony_ci	DBG(2, ">> sane_init (version %s null, authorize %s null): " PACKAGE " " VERSION "\n",
146141cc406Sopenharmony_ci	    (vc) ? "!=" : "==", (cb) ? "!=" : "==");
147141cc406Sopenharmony_ci#endif
148141cc406Sopenharmony_ci
149141cc406Sopenharmony_ci	if(vc)
150141cc406Sopenharmony_ci		*vc = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
151141cc406Sopenharmony_ci
152141cc406Sopenharmony_ci	DBG(2,"sane_init: >> ieee1284_find_ports\n");
153141cc406Sopenharmony_ci	/* Find lp ports */
154141cc406Sopenharmony_ci	tmp = ieee1284_find_ports(&pl, 0);
155141cc406Sopenharmony_ci	DBG(2,"sane_init: %d << ieee1284_find_ports\n", tmp);
156141cc406Sopenharmony_ci
157141cc406Sopenharmony_ci	if (tmp != E1284_OK)
158141cc406Sopenharmony_ci	{
159141cc406Sopenharmony_ci		DBG(1,"sane_init: Error trying to get port list\n");
160141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
161141cc406Sopenharmony_ci	}
162141cc406Sopenharmony_ci
163141cc406Sopenharmony_ci
164141cc406Sopenharmony_ci	if (pl.portc < 1)
165141cc406Sopenharmony_ci	{
166141cc406Sopenharmony_ci		DBG(1,"sane_init: Error, no parallel ports found.\n");
167141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
168141cc406Sopenharmony_ci	}
169141cc406Sopenharmony_ci
170141cc406Sopenharmony_ci	DBG(10,"sane_init: %i parallel port(s) found.\n", pl.portc);
171141cc406Sopenharmony_ci	/* Setup data structures for each port */
172141cc406Sopenharmony_ci	for(i=0; i<pl.portc; i++)
173141cc406Sopenharmony_ci	{
174141cc406Sopenharmony_ci		DBG(10,"sane_init: port %s\n", pl.portv[i]->name);
175141cc406Sopenharmony_ci		status = init_device(pl.portv[i]);
176141cc406Sopenharmony_ci		/* Now's a good time to quit if we got an error */
177141cc406Sopenharmony_ci		if (status != SANE_STATUS_GOOD) return status;
178141cc406Sopenharmony_ci	}
179141cc406Sopenharmony_ci
180141cc406Sopenharmony_ci	/* This should never be true here */
181141cc406Sopenharmony_ci	if (num_devices == 0)
182141cc406Sopenharmony_ci		status = SANE_STATUS_IO_ERROR;
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_ci	/* just to be extra sure, the line will always have an end: */
185141cc406Sopenharmony_ci	line[sizeof(line)-1] = '\0';
186141cc406Sopenharmony_ci
187141cc406Sopenharmony_ci	/*
188141cc406Sopenharmony_ci	 * Read information from config file: pixel weight location and default
189141cc406Sopenharmony_ci	 * port.
190141cc406Sopenharmony_ci	 */
191141cc406Sopenharmony_ci	if((fp = sanei_config_open(CANONP_CONFIG_FILE)))
192141cc406Sopenharmony_ci	{
193141cc406Sopenharmony_ci		while(sanei_config_read(line, sizeof (line) - 1, fp))
194141cc406Sopenharmony_ci		{
195141cc406Sopenharmony_ci			DBG(100, "sane_init: >%s<\n", line);
196141cc406Sopenharmony_ci			if(line[0] == '#')	/* ignore line comments */
197141cc406Sopenharmony_ci				continue;
198141cc406Sopenharmony_ci			if(!strlen(line))
199141cc406Sopenharmony_ci				continue;	/* ignore empty lines */
200141cc406Sopenharmony_ci
201141cc406Sopenharmony_ci			if(strncmp(line,"calibrate ", 10) == 0)
202141cc406Sopenharmony_ci			{
203141cc406Sopenharmony_ci				/* warning: pointer trickyness ahead
204141cc406Sopenharmony_ci				 * Do not free tmp_port! */
205141cc406Sopenharmony_ci				DBG(40, "sane_init: calibrate line, %s\n",
206141cc406Sopenharmony_ci						line);
207141cc406Sopenharmony_ci				tmp_wf = strdup(line+10);
208141cc406Sopenharmony_ci				tmp_port = strstr(tmp_wf, " ");
209141cc406Sopenharmony_ci				if ((tmp_port == tmp_wf) || (tmp_port == NULL))
210141cc406Sopenharmony_ci				{
211141cc406Sopenharmony_ci					/* They have used an old style config
212141cc406Sopenharmony_ci					 * file which does not specify scanner
213141cc406Sopenharmony_ci					 * Assume first port */
214141cc406Sopenharmony_ci					DBG(1, "sane_init: old config line:"
215141cc406Sopenharmony_ci							"\"%s\".  Please add "
216141cc406Sopenharmony_ci							"a port argument.\n",
217141cc406Sopenharmony_ci							line);
218141cc406Sopenharmony_ci
219141cc406Sopenharmony_ci					/* first_dev should never be null here
220141cc406Sopenharmony_ci					 * because we found at least one
221141cc406Sopenharmony_ci					 * parallel port above */
222141cc406Sopenharmony_ci					first_dev->weights_file = tmp_wf;
223141cc406Sopenharmony_ci					DBG(100, "sane_init: Successfully "
224141cc406Sopenharmony_ci							"parsed (old) cal, "
225141cc406Sopenharmony_ci							"weight file is "
226141cc406Sopenharmony_ci							"'%s'.\n", tmp_wf);
227141cc406Sopenharmony_ci					continue;
228141cc406Sopenharmony_ci
229141cc406Sopenharmony_ci				}
230141cc406Sopenharmony_ci
231141cc406Sopenharmony_ci				/* Now find which scanner wants
232141cc406Sopenharmony_ci				 * this calibration file */
233141cc406Sopenharmony_ci				s_tmp = first_dev;
234141cc406Sopenharmony_ci				DBG(100, "sane_init: Finding scanner on port "
235141cc406Sopenharmony_ci						"'%s'\n", tmp_port+1);
236141cc406Sopenharmony_ci				while (s_tmp != NULL)
237141cc406Sopenharmony_ci				{
238141cc406Sopenharmony_ci					if (!strcmp(s_tmp->params.port->name,
239141cc406Sopenharmony_ci								tmp_port+1))
240141cc406Sopenharmony_ci					{
241141cc406Sopenharmony_ci						DBG(100, "sane_init: Found!\n");
242141cc406Sopenharmony_ci						/* Now terminate the weight
243141cc406Sopenharmony_ci						 * file string */
244141cc406Sopenharmony_ci						*tmp_port = '\0';
245141cc406Sopenharmony_ci						s_tmp->weights_file = tmp_wf;
246141cc406Sopenharmony_ci						DBG(100, "sane_init: Parsed "
247141cc406Sopenharmony_ci								"cal, for port"
248141cc406Sopenharmony_ci								" '%s', weight"
249141cc406Sopenharmony_ci								" file is '%s'"
250141cc406Sopenharmony_ci								".\n",
251141cc406Sopenharmony_ci								s_tmp->params.
252141cc406Sopenharmony_ci								  port->name,
253141cc406Sopenharmony_ci								tmp_wf);
254141cc406Sopenharmony_ci						break;
255141cc406Sopenharmony_ci					}
256141cc406Sopenharmony_ci					s_tmp = s_tmp->next;
257141cc406Sopenharmony_ci				}
258141cc406Sopenharmony_ci				if (s_tmp == NULL)
259141cc406Sopenharmony_ci				{
260141cc406Sopenharmony_ci					/* we made it all the way through the
261141cc406Sopenharmony_ci					 * list and didn't find the port */
262141cc406Sopenharmony_ci					free(tmp_wf);
263141cc406Sopenharmony_ci					DBG(10, "sane_init: calibrate line is "
264141cc406Sopenharmony_ci							"for unknown port!\n");
265141cc406Sopenharmony_ci				}
266141cc406Sopenharmony_ci				continue;
267141cc406Sopenharmony_ci			}
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci
270141cc406Sopenharmony_ci			if(strncmp(line,"ieee1284 ", 9) == 0)
271141cc406Sopenharmony_ci			{
272141cc406Sopenharmony_ci				DBG(100, "sane_init: Successfully parsed "
273141cc406Sopenharmony_ci						"default scanner.\n");
274141cc406Sopenharmony_ci				/* this will be our default scanner */
275141cc406Sopenharmony_ci				def_scanner = strdup(line+9);
276141cc406Sopenharmony_ci				continue;
277141cc406Sopenharmony_ci			}
278141cc406Sopenharmony_ci
279141cc406Sopenharmony_ci			if(strncmp(line,"force_nibble", 12) == 0)
280141cc406Sopenharmony_ci			{
281141cc406Sopenharmony_ci				DBG(100, "sane_init: force_nibble "
282141cc406Sopenharmony_ci						"requested.\n");
283141cc406Sopenharmony_ci				force_nibble = SANE_TRUE;
284141cc406Sopenharmony_ci				continue;
285141cc406Sopenharmony_ci			}
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_ci			if(strncmp(line,"init_mode ", 10) == 0)
288141cc406Sopenharmony_ci			{
289141cc406Sopenharmony_ci
290141cc406Sopenharmony_ci				/* parse what sort of initialisation mode to
291141cc406Sopenharmony_ci				 * use */
292141cc406Sopenharmony_ci				if (strncmp(line+10, "FB620P", 6) == 0)
293141cc406Sopenharmony_ci					tmp_im = INITMODE_20P;
294141cc406Sopenharmony_ci				else if (strncmp(line+10, "FB630P", 6) == 0)
295141cc406Sopenharmony_ci					tmp_im = INITMODE_30P;
296141cc406Sopenharmony_ci				else if (strncmp(line+10, "AUTO", 4) == 0)
297141cc406Sopenharmony_ci					tmp_im = INITMODE_AUTO;
298141cc406Sopenharmony_ci
299141cc406Sopenharmony_ci				/* now work out which port it blongs to */
300141cc406Sopenharmony_ci
301141cc406Sopenharmony_ci				tmp_port = strstr(line+10, " ");
302141cc406Sopenharmony_ci
303141cc406Sopenharmony_ci				if (tmp_port == NULL)
304141cc406Sopenharmony_ci				{
305141cc406Sopenharmony_ci					/* first_dev should never be null here
306141cc406Sopenharmony_ci					 * because we found at least one
307141cc406Sopenharmony_ci					 * parallel port above */
308141cc406Sopenharmony_ci					first_dev->init_mode = tmp_im;
309141cc406Sopenharmony_ci					DBG(100, "sane_init: Parsed init-1.\n");
310141cc406Sopenharmony_ci					continue;
311141cc406Sopenharmony_ci				}
312141cc406Sopenharmony_ci
313141cc406Sopenharmony_ci
314141cc406Sopenharmony_ci				s_tmp = first_dev;
315141cc406Sopenharmony_ci				while (s_tmp != NULL)
316141cc406Sopenharmony_ci				{
317141cc406Sopenharmony_ci					if (!strcmp(s_tmp->params.port->name,
318141cc406Sopenharmony_ci								tmp_port+1))
319141cc406Sopenharmony_ci					{
320141cc406Sopenharmony_ci						s_tmp->init_mode = tmp_im;
321141cc406Sopenharmony_ci						DBG(100, "sane_init: Parsed "
322141cc406Sopenharmony_ci								"init.\n");
323141cc406Sopenharmony_ci						break;
324141cc406Sopenharmony_ci					}
325141cc406Sopenharmony_ci					s_tmp = s_tmp->next;
326141cc406Sopenharmony_ci				}
327141cc406Sopenharmony_ci				if (s_tmp == NULL)
328141cc406Sopenharmony_ci				{
329141cc406Sopenharmony_ci					/* we made it all the way through the
330141cc406Sopenharmony_ci					 * list and didn't find the port */
331141cc406Sopenharmony_ci					DBG(10, "sane_init: init_mode line is "
332141cc406Sopenharmony_ci							"for unknown port!\n");
333141cc406Sopenharmony_ci				}
334141cc406Sopenharmony_ci
335141cc406Sopenharmony_ci				continue;
336141cc406Sopenharmony_ci			}
337141cc406Sopenharmony_ci			DBG(1, "sane_init: Unknown configuration command!");
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci		}
340141cc406Sopenharmony_ci		fclose (fp);
341141cc406Sopenharmony_ci	}
342141cc406Sopenharmony_ci
343141cc406Sopenharmony_ci	/* There should now be a LL of ports starting at first_dev */
344141cc406Sopenharmony_ci
345141cc406Sopenharmony_ci	for (s_tmp = first_dev; s_tmp != NULL; s_tmp = s_tmp->next)
346141cc406Sopenharmony_ci	{
347141cc406Sopenharmony_ci		/* Assume there's no scanner present until proven otherwise */
348141cc406Sopenharmony_ci		s_tmp->scanner_present = SANE_FALSE;
349141cc406Sopenharmony_ci
350141cc406Sopenharmony_ci		/* Try to detect if there's a scanner there, and if so,
351141cc406Sopenharmony_ci		 * what sort of scanner it is */
352141cc406Sopenharmony_ci		status = detect_mode(s_tmp);
353141cc406Sopenharmony_ci
354141cc406Sopenharmony_ci		if (status != SANE_STATUS_GOOD)
355141cc406Sopenharmony_ci		{
356141cc406Sopenharmony_ci			DBG(10,"sane_init: Error detecting port mode on %s!\n",
357141cc406Sopenharmony_ci					s_tmp->params.port->name);
358141cc406Sopenharmony_ci			s_tmp->scanner_present = SANE_FALSE;
359141cc406Sopenharmony_ci			continue;
360141cc406Sopenharmony_ci		}
361141cc406Sopenharmony_ci
362141cc406Sopenharmony_ci		/* detect_mode succeeded, so the port is open.  This beholdens
363141cc406Sopenharmony_ci		 * us to call ieee1284_close in any of the remaining error
364141cc406Sopenharmony_ci		 * cases in this loop. */
365141cc406Sopenharmony_ci#if 0
366141cc406Sopenharmony_ci		tmp = sanei_canon_pp_detect(s_tmp->params.port,
367141cc406Sopenharmony_ci				s_tmp->init_mode);
368141cc406Sopenharmony_ci
369141cc406Sopenharmony_ci
370141cc406Sopenharmony_ci		if (tmp && (s_tmp->ieee1284_mode != M1284_NIBBLE))
371141cc406Sopenharmony_ci		{
372141cc406Sopenharmony_ci			/* A failure, try again in nibble mode... */
373141cc406Sopenharmony_ci			DBG(1, "sane_init: Failed on ECP mode, falling "
374141cc406Sopenharmony_ci					"back to nibble mode\n");
375141cc406Sopenharmony_ci
376141cc406Sopenharmony_ci			s_tmp->ieee1284_mode = M1284_NIBBLE;
377141cc406Sopenharmony_ci			sanei_canon_pp_set_ieee1284_mode(s_tmp->ieee1284_mode);
378141cc406Sopenharmony_ci			tmp = sanei_canon_pp_detect(s_tmp->params.port,
379141cc406Sopenharmony_ci					s_tmp->init_mode);
380141cc406Sopenharmony_ci		}
381141cc406Sopenharmony_ci		/* still no go? */
382141cc406Sopenharmony_ci		if (tmp)
383141cc406Sopenharmony_ci		{
384141cc406Sopenharmony_ci			DBG(1,"sane_init: couldn't find a scanner on port "
385141cc406Sopenharmony_ci					"%s\n", s_tmp->params.port->name);
386141cc406Sopenharmony_ci
387141cc406Sopenharmony_ci			ieee1284_close(s_tmp->params.port);
388141cc406Sopenharmony_ci			continue;
389141cc406Sopenharmony_ci		}
390141cc406Sopenharmony_ci
391141cc406Sopenharmony_ci#endif
392141cc406Sopenharmony_ci		/* all signs point to yes, try it out */
393141cc406Sopenharmony_ci		if (ieee1284_claim(s_tmp->params.port) != E1284_OK) {
394141cc406Sopenharmony_ci			DBG(10, "sane_init: Couldn't claim port %s.\n",
395141cc406Sopenharmony_ci				s_tmp->params.port->name);
396141cc406Sopenharmony_ci
397141cc406Sopenharmony_ci			ieee1284_close(s_tmp->params.port);
398141cc406Sopenharmony_ci			continue;
399141cc406Sopenharmony_ci		}
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci		DBG(2, "sane_init: >> initialise\n");
402141cc406Sopenharmony_ci		tmp = sanei_canon_pp_initialise(&(s_tmp->params),
403141cc406Sopenharmony_ci				s_tmp->init_mode);
404141cc406Sopenharmony_ci		DBG(2, "sane_init: << %d initialise\n", tmp);
405141cc406Sopenharmony_ci		if (tmp) {
406141cc406Sopenharmony_ci			DBG(10, "sane_init: Couldn't contact scanner on port "
407141cc406Sopenharmony_ci				"%s. Probably no scanner there?\n",
408141cc406Sopenharmony_ci				s_tmp->params.port->name);
409141cc406Sopenharmony_ci			ieee1284_release(s_tmp->params.port);
410141cc406Sopenharmony_ci			ieee1284_close(s_tmp->params.port);
411141cc406Sopenharmony_ci			s_tmp->scanner_present = SANE_FALSE;
412141cc406Sopenharmony_ci			continue;
413141cc406Sopenharmony_ci		}
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci		/* put it back to sleep until we're ready to
416141cc406Sopenharmony_ci		 * open for business again - this will only work
417141cc406Sopenharmony_ci		 * if we actually have a scanner there! */
418141cc406Sopenharmony_ci		DBG(100, "sane_init: And back to sleep again\n");
419141cc406Sopenharmony_ci		sanei_canon_pp_sleep_scanner(s_tmp->params.port);
420141cc406Sopenharmony_ci
421141cc406Sopenharmony_ci		/* leave the port open but not claimed - this is regardless
422141cc406Sopenharmony_ci		 * of the return value of initialise */
423141cc406Sopenharmony_ci		ieee1284_release(s_tmp->params.port);
424141cc406Sopenharmony_ci
425141cc406Sopenharmony_ci		/* Finally, we're sure there's a scanner there! Now we
426141cc406Sopenharmony_ci		 * just have to load the weights file...*/
427141cc406Sopenharmony_ci
428141cc406Sopenharmony_ci		if (fix_weights_file(s_tmp) != SANE_STATUS_GOOD) {
429141cc406Sopenharmony_ci			DBG(1, "sane_init: Eeek! fix_weights_file failed for "
430141cc406Sopenharmony_ci				"scanner on port %s!\n",
431141cc406Sopenharmony_ci				s_tmp->params.port->name);
432141cc406Sopenharmony_ci			/* non-fatal.. scans will look ugly as sin unless
433141cc406Sopenharmony_ci			 * they calibrate */
434141cc406Sopenharmony_ci		}
435141cc406Sopenharmony_ci
436141cc406Sopenharmony_ci		/* Cocked, locked and ready to rock */
437141cc406Sopenharmony_ci		s_tmp->hw.model = s_tmp->params.name;
438141cc406Sopenharmony_ci		s_tmp->scanner_present = SANE_TRUE;
439141cc406Sopenharmony_ci	}
440141cc406Sopenharmony_ci
441141cc406Sopenharmony_ci	DBG(2, "<< sane_init\n");
442141cc406Sopenharmony_ci
443141cc406Sopenharmony_ci	return status;
444141cc406Sopenharmony_ci}
445141cc406Sopenharmony_ci
446141cc406Sopenharmony_ci
447141cc406Sopenharmony_ci/*************************************************************************
448141cc406Sopenharmony_ci *
449141cc406Sopenharmony_ci * sane_get_devices()
450141cc406Sopenharmony_ci *
451141cc406Sopenharmony_ci * Gives a list of devices available.  In our case, that's the linked
452141cc406Sopenharmony_ci * list produced by sane_init.
453141cc406Sopenharmony_ci *
454141cc406Sopenharmony_ci *************************************************************************/
455141cc406Sopenharmony_ci	SANE_Status
456141cc406Sopenharmony_cisane_get_devices (const SANE_Device ***dl, SANE_Bool local)
457141cc406Sopenharmony_ci{
458141cc406Sopenharmony_ci	static const SANE_Device **devlist;
459141cc406Sopenharmony_ci	CANONP_Scanner *dev;
460141cc406Sopenharmony_ci	int i;
461141cc406Sopenharmony_ci
462141cc406Sopenharmony_ci	DBG(2, ">> sane_get_devices (%p, %d)\n", (const void*)dl, local);
463141cc406Sopenharmony_ci
464141cc406Sopenharmony_ci	if (dl == NULL)
465141cc406Sopenharmony_ci	{
466141cc406Sopenharmony_ci		DBG(1, "sane_get_devices: ERROR: devlist pointer is NULL!");
467141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
468141cc406Sopenharmony_ci	}
469141cc406Sopenharmony_ci
470141cc406Sopenharmony_ci	if (devlist != NULL)
471141cc406Sopenharmony_ci	{
472141cc406Sopenharmony_ci		/* this has been called already */
473141cc406Sopenharmony_ci		*dl = devlist;
474141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
475141cc406Sopenharmony_ci	}
476141cc406Sopenharmony_ci	devlist = malloc((num_devices + 1) * sizeof(*devlist));
477141cc406Sopenharmony_ci	if (devlist == NULL)
478141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
479141cc406Sopenharmony_ci
480141cc406Sopenharmony_ci	i = 0;
481141cc406Sopenharmony_ci	for (dev = first_dev; dev != NULL; dev = dev->next)
482141cc406Sopenharmony_ci	{
483141cc406Sopenharmony_ci		if (dev->scanner_present == SANE_TRUE)
484141cc406Sopenharmony_ci		{
485141cc406Sopenharmony_ci			devlist[i] = &(dev->hw);
486141cc406Sopenharmony_ci			i++;
487141cc406Sopenharmony_ci		}
488141cc406Sopenharmony_ci	}
489141cc406Sopenharmony_ci
490141cc406Sopenharmony_ci	devlist[i] = NULL;
491141cc406Sopenharmony_ci
492141cc406Sopenharmony_ci	*dl = devlist;
493141cc406Sopenharmony_ci
494141cc406Sopenharmony_ci	DBG(2, "<< sane_get_devices\n");
495141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
496141cc406Sopenharmony_ci}
497141cc406Sopenharmony_ci
498141cc406Sopenharmony_ci
499141cc406Sopenharmony_ci/*************************************************************************
500141cc406Sopenharmony_ci *
501141cc406Sopenharmony_ci * sane_open()
502141cc406Sopenharmony_ci *
503141cc406Sopenharmony_ci * Open the scanner described by name.  Ask libieee1284 to claim the port
504141cc406Sopenharmony_ci * and call Simon's init code.  Also configure data structures.
505141cc406Sopenharmony_ci *
506141cc406Sopenharmony_ci *************************************************************************/
507141cc406Sopenharmony_ci	SANE_Status
508141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle *h)
509141cc406Sopenharmony_ci{
510141cc406Sopenharmony_ci	CANONP_Scanner *cs;
511141cc406Sopenharmony_ci	SANE_Range *tmp_range;
512141cc406Sopenharmony_ci	int tmp;
513141cc406Sopenharmony_ci
514141cc406Sopenharmony_ci	DBG(2, ">> sane_open (h=%p, name=\"%s\")\n", (void *)h, name);
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci	if ((h == NULL) || (name == NULL))
517141cc406Sopenharmony_ci	{
518141cc406Sopenharmony_ci		DBG(2,"sane_open: Null pointer received!\n");
519141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
520141cc406Sopenharmony_ci	}
521141cc406Sopenharmony_ci
522141cc406Sopenharmony_ci	if (!strlen(name))
523141cc406Sopenharmony_ci	{
524141cc406Sopenharmony_ci		DBG(10,"sane_open: Empty name given, assuming first/"
525141cc406Sopenharmony_ci				"default scanner\n");
526141cc406Sopenharmony_ci		if (def_scanner == NULL)
527141cc406Sopenharmony_ci			name = first_dev->params.port->name;
528141cc406Sopenharmony_ci		else
529141cc406Sopenharmony_ci			name = def_scanner;
530141cc406Sopenharmony_ci
531141cc406Sopenharmony_ci		/* we don't _have_ to fit this name, so _don't_ fail if it's
532141cc406Sopenharmony_ci		 * not there */
533141cc406Sopenharmony_ci
534141cc406Sopenharmony_ci		cs = first_dev;
535141cc406Sopenharmony_ci		while((cs != NULL) && strcmp(cs->params.port->name, name))
536141cc406Sopenharmony_ci			cs = cs->next;
537141cc406Sopenharmony_ci
538141cc406Sopenharmony_ci		/* if we didn't find the port they want, or there's no scanner
539141cc406Sopenharmony_ci		 * there, we just want to find _any_ scanner */
540141cc406Sopenharmony_ci		if ((cs == NULL) || (cs->scanner_present != SANE_TRUE))
541141cc406Sopenharmony_ci		{
542141cc406Sopenharmony_ci			cs = first_dev;
543141cc406Sopenharmony_ci			while((cs != NULL) &&
544141cc406Sopenharmony_ci					(cs->scanner_present == SANE_FALSE))
545141cc406Sopenharmony_ci				cs = cs->next;
546141cc406Sopenharmony_ci		}
547141cc406Sopenharmony_ci
548141cc406Sopenharmony_ci	} else {
549141cc406Sopenharmony_ci
550141cc406Sopenharmony_ci		/* they're dead keen for this name, so _do_ fail if it's
551141cc406Sopenharmony_ci		 * not there */
552141cc406Sopenharmony_ci		cs = first_dev;
553141cc406Sopenharmony_ci		while((cs != NULL) && strcmp(cs->params.port->name, name))
554141cc406Sopenharmony_ci			cs = cs->next;
555141cc406Sopenharmony_ci	}
556141cc406Sopenharmony_ci
557141cc406Sopenharmony_ci
558141cc406Sopenharmony_ci	if (cs == NULL)
559141cc406Sopenharmony_ci	{
560141cc406Sopenharmony_ci		DBG(2,"sane_open: No scanner found or requested port "
561141cc406Sopenharmony_ci				"doesn't exist (%s)\n", name);
562141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
563141cc406Sopenharmony_ci	}
564141cc406Sopenharmony_ci	if (cs->scanner_present == SANE_FALSE)
565141cc406Sopenharmony_ci	{
566141cc406Sopenharmony_ci		DBG(1,"sane_open: Request to open port with no scanner "
567141cc406Sopenharmony_ci				"(%s)\n", name);
568141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
569141cc406Sopenharmony_ci	}
570141cc406Sopenharmony_ci	if (cs->opened == SANE_TRUE)
571141cc406Sopenharmony_ci	{
572141cc406Sopenharmony_ci		DBG(2,"sane_open; Oi!, That scanner's already open.\n");
573141cc406Sopenharmony_ci		return SANE_STATUS_DEVICE_BUSY;
574141cc406Sopenharmony_ci	}
575141cc406Sopenharmony_ci
576141cc406Sopenharmony_ci	/* If the scanner has already been opened once, we don't have to do
577141cc406Sopenharmony_ci	 * this setup again */
578141cc406Sopenharmony_ci	if (cs->setup == SANE_TRUE)
579141cc406Sopenharmony_ci	{
580141cc406Sopenharmony_ci		cs->opened = SANE_TRUE;
581141cc406Sopenharmony_ci		*h = (SANE_Handle)cs;
582141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
583141cc406Sopenharmony_ci	}
584141cc406Sopenharmony_ci
585141cc406Sopenharmony_ci	tmp = ieee1284_claim(cs->params.port);
586141cc406Sopenharmony_ci	if (tmp != E1284_OK) {
587141cc406Sopenharmony_ci		DBG(1, "sane_open: Could not claim port!\n");
588141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
589141cc406Sopenharmony_ci	}
590141cc406Sopenharmony_ci
591141cc406Sopenharmony_ci	/* I put the scanner to sleep before, better wake it back up */
592141cc406Sopenharmony_ci
593141cc406Sopenharmony_ci	DBG(2, "sane_open: >> initialise\n");
594141cc406Sopenharmony_ci	tmp = sanei_canon_pp_initialise(&(cs->params), cs->init_mode);
595141cc406Sopenharmony_ci	DBG(2, "sane_open: << %d initialise\n", tmp);
596141cc406Sopenharmony_ci	if (tmp != 0) {
597141cc406Sopenharmony_ci		DBG(1, "sane_open: initialise returned %d, something is "
598141cc406Sopenharmony_ci				"wrong with the scanner!\n", tmp);
599141cc406Sopenharmony_ci
600141cc406Sopenharmony_ci		DBG(1, "sane_open: Can't contact scanner.  Try power "
601141cc406Sopenharmony_ci				"cycling scanner, and unplug any "
602141cc406Sopenharmony_ci				"printers\n");
603141cc406Sopenharmony_ci		ieee1284_release(cs->params.port);
604141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
605141cc406Sopenharmony_ci	}
606141cc406Sopenharmony_ci
607141cc406Sopenharmony_ci	if (cs->weights_file != NULL)
608141cc406Sopenharmony_ci		DBG(2, "sane_open: >> load_weights(%s, %p)\n",
609141cc406Sopenharmony_ci				cs->weights_file,
610141cc406Sopenharmony_ci				(const void *)(&(cs->params)));
611141cc406Sopenharmony_ci	else
612141cc406Sopenharmony_ci		DBG(2, "sane_open: >> load_weights(NULL, %p)\n",
613141cc406Sopenharmony_ci				(const void *)(&(cs->params)));
614141cc406Sopenharmony_ci	tmp = sanei_canon_pp_load_weights(cs->weights_file, &(cs->params));
615141cc406Sopenharmony_ci	DBG(2, "sane_open: << %d load_weights\n", tmp);
616141cc406Sopenharmony_ci
617141cc406Sopenharmony_ci	if (tmp != 0) {
618141cc406Sopenharmony_ci		DBG(1, "sane_open: WARNING: Error on load_weights: "
619141cc406Sopenharmony_ci				"returned %d.  This could be due to a corrupt "
620141cc406Sopenharmony_ci				"calibration file.  Try recalibrating and if "
621141cc406Sopenharmony_ci				"problems persist, please report the problem "
622141cc406Sopenharmony_ci				"to the canon_pp maintainer\n", tmp);
623141cc406Sopenharmony_ci		cs->cal_valid = SANE_FALSE;
624141cc406Sopenharmony_ci	} else {
625141cc406Sopenharmony_ci		cs->cal_valid = SANE_TRUE;
626141cc406Sopenharmony_ci		DBG(10, "sane_open: loadweights successful, uploading gamma"
627141cc406Sopenharmony_ci				" profile...\n");
628141cc406Sopenharmony_ci		tmp = sanei_canon_pp_adjust_gamma(&(cs->params));
629141cc406Sopenharmony_ci		if (tmp != 0)
630141cc406Sopenharmony_ci			DBG(1, "sane_open: WARNING: adjust_gamma returned "
631141cc406Sopenharmony_ci					"%d!\n", tmp);
632141cc406Sopenharmony_ci
633141cc406Sopenharmony_ci		DBG(10, "sane_open: after adjust_gamma Status = %i\n",
634141cc406Sopenharmony_ci				sanei_canon_pp_check_status(cs->params.port));
635141cc406Sopenharmony_ci	}
636141cc406Sopenharmony_ci
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci	/* Configure ranges etc */
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci	/* Resolution - determined by magic number */
641141cc406Sopenharmony_ci
642141cc406Sopenharmony_ci	if (cs->params.scanheadwidth == 2552)
643141cc406Sopenharmony_ci		cs->opt[OPT_RESOLUTION].constraint.word_list = res300;
644141cc406Sopenharmony_ci	else
645141cc406Sopenharmony_ci		cs->opt[OPT_RESOLUTION].constraint.word_list = res600;
646141cc406Sopenharmony_ci
647141cc406Sopenharmony_ci
648141cc406Sopenharmony_ci	/* TL-X */
649141cc406Sopenharmony_ci	if(!(tmp_range = malloc(sizeof(*tmp_range))))
650141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
651141cc406Sopenharmony_ci	(*tmp_range).min = 0;
652141cc406Sopenharmony_ci	(*tmp_range).max = 215;
653141cc406Sopenharmony_ci	cs->opt[OPT_TL_X].constraint.range = tmp_range;
654141cc406Sopenharmony_ci
655141cc406Sopenharmony_ci	/* TL-Y */
656141cc406Sopenharmony_ci	if(!(tmp_range = malloc(sizeof(*tmp_range))))
657141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
658141cc406Sopenharmony_ci	(*tmp_range).min = 0;
659141cc406Sopenharmony_ci	(*tmp_range).max = 296;
660141cc406Sopenharmony_ci	cs->opt[OPT_TL_Y].constraint.range = tmp_range;
661141cc406Sopenharmony_ci
662141cc406Sopenharmony_ci	/* BR-X */
663141cc406Sopenharmony_ci	if(!(tmp_range = malloc(sizeof(*tmp_range))))
664141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
665141cc406Sopenharmony_ci	(*tmp_range).min = 3;
666141cc406Sopenharmony_ci	(*tmp_range).max = 216;
667141cc406Sopenharmony_ci	cs->opt[OPT_BR_X].constraint.range = tmp_range;
668141cc406Sopenharmony_ci
669141cc406Sopenharmony_ci	/* BR-Y */
670141cc406Sopenharmony_ci	if(!(tmp_range = malloc(sizeof(*tmp_range))))
671141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
672141cc406Sopenharmony_ci	(*tmp_range).min = 1;
673141cc406Sopenharmony_ci	(*tmp_range).max = 297;
674141cc406Sopenharmony_ci	cs->opt[OPT_BR_Y].constraint.range = tmp_range;
675141cc406Sopenharmony_ci
676141cc406Sopenharmony_ci
677141cc406Sopenharmony_ci	cs->opened = SANE_TRUE;
678141cc406Sopenharmony_ci	cs->setup = SANE_TRUE;
679141cc406Sopenharmony_ci
680141cc406Sopenharmony_ci	*h = (SANE_Handle)cs;
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ci	DBG(2, "<< sane_open\n");
683141cc406Sopenharmony_ci
684141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
685141cc406Sopenharmony_ci}
686141cc406Sopenharmony_ci
687141cc406Sopenharmony_ci/*************************************************************************
688141cc406Sopenharmony_ci *
689141cc406Sopenharmony_ci * sane_get_option_descriptor()
690141cc406Sopenharmony_ci *
691141cc406Sopenharmony_ci * Return the structure for option number opt.
692141cc406Sopenharmony_ci *
693141cc406Sopenharmony_ci *************************************************************************/
694141cc406Sopenharmony_ci	const SANE_Option_Descriptor *
695141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle h, SANE_Int opt)
696141cc406Sopenharmony_ci{
697141cc406Sopenharmony_ci	CANONP_Scanner *cs = ((CANONP_Scanner *)h);
698141cc406Sopenharmony_ci	/*DBG(2, ">> sane_get_option_descriptor (h=%p, opt=%d)\n", h, opt);*/
699141cc406Sopenharmony_ci
700141cc406Sopenharmony_ci	if (h == NULL) {
701141cc406Sopenharmony_ci		DBG(10,"sane_get_option_descriptor: WARNING: h==NULL!\n");
702141cc406Sopenharmony_ci		return NULL;
703141cc406Sopenharmony_ci	}
704141cc406Sopenharmony_ci
705141cc406Sopenharmony_ci	if ((unsigned)opt >= NUM_OPTIONS) {
706141cc406Sopenharmony_ci		DBG(10,"sane_get_option_descriptor: Note: opt >= "
707141cc406Sopenharmony_ci				"NUM_OPTIONS!\n");
708141cc406Sopenharmony_ci		return NULL;
709141cc406Sopenharmony_ci	}
710141cc406Sopenharmony_ci
711141cc406Sopenharmony_ci	if (cs->opened == SANE_FALSE)
712141cc406Sopenharmony_ci	{
713141cc406Sopenharmony_ci		DBG(1,"sane_get_option_descriptor: That scanner (%p) ain't "
714141cc406Sopenharmony_ci				"open yet\n", h);
715141cc406Sopenharmony_ci		return NULL;
716141cc406Sopenharmony_ci	}
717141cc406Sopenharmony_ci
718141cc406Sopenharmony_ci	/*DBG(2, "<< sane_get_option_descriptor\n");*/
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci	return (cs->opt + opt);
721141cc406Sopenharmony_ci}
722141cc406Sopenharmony_ci
723141cc406Sopenharmony_ci
724141cc406Sopenharmony_ci/*************************************************************************
725141cc406Sopenharmony_ci *
726141cc406Sopenharmony_ci * sane_control_option()
727141cc406Sopenharmony_ci *
728141cc406Sopenharmony_ci * Set a value for one of the options provided.
729141cc406Sopenharmony_ci *
730141cc406Sopenharmony_ci *************************************************************************/
731141cc406Sopenharmony_ciSANE_Status
732141cc406Sopenharmony_cisane_control_option (SANE_Handle h, SANE_Int opt, SANE_Action act,
733141cc406Sopenharmony_ci		void *val, SANE_Word *info)
734141cc406Sopenharmony_ci{
735141cc406Sopenharmony_ci	CANONP_Scanner *cs = ((CANONP_Scanner *)h);
736141cc406Sopenharmony_ci	int i = 0, tmp, maxresi;
737141cc406Sopenharmony_ci
738141cc406Sopenharmony_ci	DBG(2, ">> sane_control_option (h=%p, opt=%d, act=%d)\n",
739141cc406Sopenharmony_ci			h,opt,act);
740141cc406Sopenharmony_ci	/* Do some sanity checks on the parameters
741141cc406Sopenharmony_ci	 * note that val can be null for buttons */
742141cc406Sopenharmony_ci	if ((h == NULL) || ((val == NULL) && (opt != OPT_CAL)))
743141cc406Sopenharmony_ci		/* || (info == NULL))  - Don't check this any more..
744141cc406Sopenharmony_ci		 * frontends seem to like passing a null */
745141cc406Sopenharmony_ci	{
746141cc406Sopenharmony_ci		DBG(1,"sane_control_option: Frontend passed me a null! "
747141cc406Sopenharmony_ci				"(h=%p,val=%p,info=%p)\n",(void*)h,
748141cc406Sopenharmony_ci				val,(void*)info);
749141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
750141cc406Sopenharmony_ci	}
751141cc406Sopenharmony_ci
752141cc406Sopenharmony_ci	if (((unsigned)opt) >= NUM_OPTIONS)
753141cc406Sopenharmony_ci	{
754141cc406Sopenharmony_ci		DBG(1,"sane_control_option: I don't do option %d.\n", opt);
755141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
756141cc406Sopenharmony_ci	}
757141cc406Sopenharmony_ci
758141cc406Sopenharmony_ci	if (cs->opened == SANE_FALSE)
759141cc406Sopenharmony_ci	{
760141cc406Sopenharmony_ci		DBG(1,"sane_control_option: That scanner (%p) ain't "
761141cc406Sopenharmony_ci				"open yet\n", h);
762141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
763141cc406Sopenharmony_ci	}
764141cc406Sopenharmony_ci
765141cc406Sopenharmony_ci	if (cs->scanning == SANE_TRUE)
766141cc406Sopenharmony_ci	{
767141cc406Sopenharmony_ci		DBG(1,"sane_control_option: That scanner (%p) is scanning!\n",
768141cc406Sopenharmony_ci				h);
769141cc406Sopenharmony_ci		return SANE_STATUS_DEVICE_BUSY;
770141cc406Sopenharmony_ci	}
771141cc406Sopenharmony_ci
772141cc406Sopenharmony_ci	switch(act)
773141cc406Sopenharmony_ci	{
774141cc406Sopenharmony_ci		case SANE_ACTION_GET_VALUE:
775141cc406Sopenharmony_ci			switch (opt)
776141cc406Sopenharmony_ci			{
777141cc406Sopenharmony_ci				case OPT_COLOUR_MODE:
778141cc406Sopenharmony_ci					strcpy((char *)val,
779141cc406Sopenharmony_ci							cmodes[cs->vals[opt]]);
780141cc406Sopenharmony_ci					break;
781141cc406Sopenharmony_ci				case OPT_DEPTH:
782141cc406Sopenharmony_ci					strcpy((char *)val,
783141cc406Sopenharmony_ci							depths[cs->vals[opt]]);
784141cc406Sopenharmony_ci					break;
785141cc406Sopenharmony_ci				case OPT_RESOLUTION:
786141cc406Sopenharmony_ci					*((int *)val) = res600[cs->vals[opt]];
787141cc406Sopenharmony_ci					break;
788141cc406Sopenharmony_ci				default:
789141cc406Sopenharmony_ci					*((int *)val) = cs->vals[opt];
790141cc406Sopenharmony_ci					break;
791141cc406Sopenharmony_ci			}
792141cc406Sopenharmony_ci			break;
793141cc406Sopenharmony_ci		case SANE_ACTION_SET_VALUE:
794141cc406Sopenharmony_ci			/* val has been checked for NULL if opt != OPT_CAL */
795141cc406Sopenharmony_ci			if (opt != OPT_CAL) i = *((int *)val);
796141cc406Sopenharmony_ci			if (info != NULL) *info = 0;
797141cc406Sopenharmony_ci			switch (opt) {
798141cc406Sopenharmony_ci				case OPT_NUM_OPTIONS:
799141cc406Sopenharmony_ci					/* you can't set that! */
800141cc406Sopenharmony_ci					return SANE_STATUS_INVAL;
801141cc406Sopenharmony_ci				case OPT_RESOLUTION:
802141cc406Sopenharmony_ci					i = cs->vals[opt];
803141cc406Sopenharmony_ci					cs->vals[opt] = 1;
804141cc406Sopenharmony_ci					maxresi = cs->opt[OPT_RESOLUTION].
805141cc406Sopenharmony_ci						constraint.word_list[0];
806141cc406Sopenharmony_ci
807141cc406Sopenharmony_ci					while ((cs->vals[opt] <= maxresi) &&
808141cc406Sopenharmony_ci							(res600[cs->vals[opt]]
809141cc406Sopenharmony_ci							 < *((int *)val)))
810141cc406Sopenharmony_ci					{
811141cc406Sopenharmony_ci						cs->vals[opt] += 1;
812141cc406Sopenharmony_ci					}
813141cc406Sopenharmony_ci
814141cc406Sopenharmony_ci					if (res600[cs->vals[opt]] !=
815141cc406Sopenharmony_ci							*((int *)val))
816141cc406Sopenharmony_ci					{
817141cc406Sopenharmony_ci						if (info != NULL) *info |=
818141cc406Sopenharmony_ci							SANE_INFO_INEXACT;
819141cc406Sopenharmony_ci					}
820141cc406Sopenharmony_ci					break;
821141cc406Sopenharmony_ci				case OPT_COLOUR_MODE:
822141cc406Sopenharmony_ci					cs->vals[opt] = 0;
823141cc406Sopenharmony_ci					while ((cmodes[cs->vals[opt]] != NULL)
824141cc406Sopenharmony_ci							&& strcmp(cmodes[cs->vals[opt]],
825141cc406Sopenharmony_ci								(char *)val))
826141cc406Sopenharmony_ci					{
827141cc406Sopenharmony_ci						cs->vals[opt] += 1;
828141cc406Sopenharmony_ci					}
829141cc406Sopenharmony_ci					if (info != NULL) *info |=
830141cc406Sopenharmony_ci						SANE_INFO_RELOAD_PARAMS;
831141cc406Sopenharmony_ci					break;
832141cc406Sopenharmony_ci				case OPT_DEPTH:
833141cc406Sopenharmony_ci					cs->vals[opt] = 0;
834141cc406Sopenharmony_ci					while ((depths[cs->vals[opt]] != NULL)
835141cc406Sopenharmony_ci							&& strcmp(depths[cs->vals[opt]],
836141cc406Sopenharmony_ci								(char *)val))
837141cc406Sopenharmony_ci					{
838141cc406Sopenharmony_ci						cs->vals[opt] += 1;
839141cc406Sopenharmony_ci					}
840141cc406Sopenharmony_ci					if (info != NULL) *info |=
841141cc406Sopenharmony_ci						SANE_INFO_RELOAD_PARAMS;
842141cc406Sopenharmony_ci					break;
843141cc406Sopenharmony_ci				case OPT_TL_X:
844141cc406Sopenharmony_ci				case OPT_BR_X:
845141cc406Sopenharmony_ci				case OPT_TL_Y:
846141cc406Sopenharmony_ci				case OPT_BR_Y:
847141cc406Sopenharmony_ci					if ((i<cs->opt[opt].constraint.range->min) || (i>cs->opt[opt].constraint.range->max))
848141cc406Sopenharmony_ci						return SANE_STATUS_INVAL;
849141cc406Sopenharmony_ci					cs->vals[opt] = i;
850141cc406Sopenharmony_ci					break;
851141cc406Sopenharmony_ci				case OPT_CAL:
852141cc406Sopenharmony_ci					/* Call the calibration code */
853141cc406Sopenharmony_ci					if ((cs->weights_file==NULL) ||
854141cc406Sopenharmony_ci							cs->cal_readonly
855141cc406Sopenharmony_ci					   )
856141cc406Sopenharmony_ci						DBG(2, ">> calibrate(x, "
857141cc406Sopenharmony_ci								"NULL)\n");
858141cc406Sopenharmony_ci					else
859141cc406Sopenharmony_ci						DBG(2, ">> calibrate(x,"
860141cc406Sopenharmony_ci								"%s)\n",
861141cc406Sopenharmony_ci								cs->weights_file);
862141cc406Sopenharmony_ci
863141cc406Sopenharmony_ci					if (cs->cal_readonly) tmp =
864141cc406Sopenharmony_ci						sanei_canon_pp_calibrate(
865141cc406Sopenharmony_ci								&(cs->params),
866141cc406Sopenharmony_ci								NULL);
867141cc406Sopenharmony_ci					else tmp = sanei_canon_pp_calibrate(
868141cc406Sopenharmony_ci							&(cs->params),
869141cc406Sopenharmony_ci							cs->weights_file);
870141cc406Sopenharmony_ci
871141cc406Sopenharmony_ci					DBG(2, "<< %d calibrate\n",
872141cc406Sopenharmony_ci							tmp);
873141cc406Sopenharmony_ci					if (tmp != 0) {
874141cc406Sopenharmony_ci						DBG(1, "sane_control_option: "
875141cc406Sopenharmony_ci								"WARNING: "
876141cc406Sopenharmony_ci								"calibrate "
877141cc406Sopenharmony_ci								"returned %d!",
878141cc406Sopenharmony_ci								tmp);
879141cc406Sopenharmony_ci						cs->cal_valid =
880141cc406Sopenharmony_ci							SANE_FALSE;
881141cc406Sopenharmony_ci						return SANE_STATUS_IO_ERROR;
882141cc406Sopenharmony_ci					} else {
883141cc406Sopenharmony_ci						cs->cal_valid =
884141cc406Sopenharmony_ci							SANE_TRUE;
885141cc406Sopenharmony_ci					}
886141cc406Sopenharmony_ci
887141cc406Sopenharmony_ci					break;
888141cc406Sopenharmony_ci					/*case OPT_PREVIEW:
889141cc406Sopenharmony_ci					  if (i) cs->vals[opt] = 1;
890141cc406Sopenharmony_ci					  else cs->vals[opt] = 0;
891141cc406Sopenharmony_ci					  break;*/
892141cc406Sopenharmony_ci				default:
893141cc406Sopenharmony_ci					/* Should never happen */
894141cc406Sopenharmony_ci					return SANE_STATUS_INVAL;
895141cc406Sopenharmony_ci			}
896141cc406Sopenharmony_ci			break;
897141cc406Sopenharmony_ci		case SANE_ACTION_SET_AUTO:
898141cc406Sopenharmony_ci			DBG(2, "sane_control_option: attempt at "
899141cc406Sopenharmony_ci					"automatic control! (unsupported)\n");
900141cc406Sopenharmony_ci			/* Auto? are they mad? I'm not that smart! */
901141cc406Sopenharmony_ci			/* fall through. */
902141cc406Sopenharmony_ci		default:
903141cc406Sopenharmony_ci			return SANE_STATUS_INVAL;
904141cc406Sopenharmony_ci	}
905141cc406Sopenharmony_ci
906141cc406Sopenharmony_ci
907141cc406Sopenharmony_ci	DBG(2, "<< sane_control_option\n");
908141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
909141cc406Sopenharmony_ci}
910141cc406Sopenharmony_ci
911141cc406Sopenharmony_ci
912141cc406Sopenharmony_ci/*************************************************************************
913141cc406Sopenharmony_ci *
914141cc406Sopenharmony_ci * sane_get_parameters()
915141cc406Sopenharmony_ci *
916141cc406Sopenharmony_ci * Get information about the next packet. If a scan hasn't started, results
917141cc406Sopenharmony_ci * only have to be best guesses.
918141cc406Sopenharmony_ci *
919141cc406Sopenharmony_ci *************************************************************************/
920141cc406Sopenharmony_ci	SANE_Status
921141cc406Sopenharmony_cisane_get_parameters (SANE_Handle h, SANE_Parameters *params)
922141cc406Sopenharmony_ci{
923141cc406Sopenharmony_ci	int res, max_width, max_height, max_res;
924141cc406Sopenharmony_ci        CANONP_Scanner *cs = ((CANONP_Scanner *)h);
925141cc406Sopenharmony_ci	DBG(2, ">> sane_get_parameters (h=%p, params=%p)\n", (void*)h,
926141cc406Sopenharmony_ci			(void*)params);
927141cc406Sopenharmony_ci
928141cc406Sopenharmony_ci	if (h == NULL) return SANE_STATUS_INVAL;
929141cc406Sopenharmony_ci
930141cc406Sopenharmony_ci	if (cs->opened == SANE_FALSE)
931141cc406Sopenharmony_ci	{
932141cc406Sopenharmony_ci		DBG(1,"sane_get_parameters: That scanner (%p) ain't "
933141cc406Sopenharmony_ci				"open yet\n", h);
934141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
935141cc406Sopenharmony_ci	}
936141cc406Sopenharmony_ci
937141cc406Sopenharmony_ci	/* We use 600 res list here because the 300 res list is just a shorter
938141cc406Sopenharmony_ci	 * version, so this will always work. */
939141cc406Sopenharmony_ci	res = res600[cs->vals[OPT_RESOLUTION]];
940141cc406Sopenharmony_ci
941141cc406Sopenharmony_ci	/*
942141cc406Sopenharmony_ci	 * These don't change whether we're scanning or not
943141cc406Sopenharmony_ci	 * NOTE: Assumes options don't change after scanning commences, which
944141cc406Sopenharmony_ci         *       is part of the standard
945141cc406Sopenharmony_ci	 */
946141cc406Sopenharmony_ci
947141cc406Sopenharmony_ci	/* Copy the options stored in the vals into the scaninfo */
948141cc406Sopenharmony_ci	params->pixels_per_line =
949141cc406Sopenharmony_ci                ((cs->vals[OPT_BR_X] - cs->vals[OPT_TL_X]) * res) / MM_PER_IN;
950141cc406Sopenharmony_ci	params->lines = ((cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y]) * res)
951141cc406Sopenharmony_ci                / MM_PER_IN;
952141cc406Sopenharmony_ci
953141cc406Sopenharmony_ci	/* FIXME: Magic numbers ahead! */
954141cc406Sopenharmony_ci
955141cc406Sopenharmony_ci	max_res = cs->params.scanheadwidth == 2552 ? 300 : 600;
956141cc406Sopenharmony_ci
957141cc406Sopenharmony_ci	/* x values have to be divisible by 4 (round down) */
958141cc406Sopenharmony_ci	params->pixels_per_line -= (params->pixels_per_line%4);
959141cc406Sopenharmony_ci
960141cc406Sopenharmony_ci        /* Can't scan less than 64 */
961141cc406Sopenharmony_ci        if (params->pixels_per_line < 64) params->pixels_per_line = 64;
962141cc406Sopenharmony_ci
963141cc406Sopenharmony_ci	max_width = cs->params.scanheadwidth / (max_res / res);
964141cc406Sopenharmony_ci
965141cc406Sopenharmony_ci	max_height = (cs->params.scanheadwidth == 2552 ? 3508 : 7016) /
966141cc406Sopenharmony_ci                                        (max_res / res);
967141cc406Sopenharmony_ci
968141cc406Sopenharmony_ci        if(params->pixels_per_line > max_width)
969141cc406Sopenharmony_ci                params->pixels_per_line = max_width;
970141cc406Sopenharmony_ci        if(params->lines > max_height) params->lines = max_height;
971141cc406Sopenharmony_ci
972141cc406Sopenharmony_ci
973141cc406Sopenharmony_ci	params->depth = cs->vals[OPT_DEPTH] ? 16 : 8;
974141cc406Sopenharmony_ci
975141cc406Sopenharmony_ci	switch (cs->vals[OPT_COLOUR_MODE])
976141cc406Sopenharmony_ci	{
977141cc406Sopenharmony_ci		case 0:
978141cc406Sopenharmony_ci			params->format = SANE_FRAME_GRAY;
979141cc406Sopenharmony_ci			break;
980141cc406Sopenharmony_ci		case 1:
981141cc406Sopenharmony_ci			params->format = SANE_FRAME_RGB;
982141cc406Sopenharmony_ci			break;
983141cc406Sopenharmony_ci		default:
984141cc406Sopenharmony_ci			/* shouldn't happen */
985141cc406Sopenharmony_ci			break;
986141cc406Sopenharmony_ci	}
987141cc406Sopenharmony_ci
988141cc406Sopenharmony_ci
989141cc406Sopenharmony_ci	if (!(params->pixels_per_line)) {
990141cc406Sopenharmony_ci		params->last_frame = SANE_TRUE;
991141cc406Sopenharmony_ci		params->lines = 0;
992141cc406Sopenharmony_ci	}
993141cc406Sopenharmony_ci
994141cc406Sopenharmony_ci	/* Always the "last frame" */
995141cc406Sopenharmony_ci	params->last_frame = SANE_TRUE;
996141cc406Sopenharmony_ci
997141cc406Sopenharmony_ci	params->bytes_per_line = params->pixels_per_line * (params->depth/8) *
998141cc406Sopenharmony_ci		(cs->vals[OPT_COLOUR_MODE] ? 3 : 1);
999141cc406Sopenharmony_ci
1000141cc406Sopenharmony_ci	DBG(10, "get_params: bytes_per_line=%d, pixels_per_line=%d, lines=%d\n"
1001141cc406Sopenharmony_ci                "max_res=%d, res=%d, max_height=%d, br_y=%d, tl_y=%d, "
1002141cc406Sopenharmony_ci		"mm_per_in=%f\n",
1003141cc406Sopenharmony_ci                params->bytes_per_line, params->pixels_per_line, params->lines,
1004141cc406Sopenharmony_ci                max_res, res, max_height, cs->vals[OPT_BR_Y],
1005141cc406Sopenharmony_ci		cs->vals[OPT_TL_Y], MM_PER_IN);
1006141cc406Sopenharmony_ci
1007141cc406Sopenharmony_ci	DBG(2, "<< sane_get_parameters\n");
1008141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1009141cc406Sopenharmony_ci}
1010141cc406Sopenharmony_ci
1011141cc406Sopenharmony_ci
1012141cc406Sopenharmony_ci/*************************************************************************
1013141cc406Sopenharmony_ci *
1014141cc406Sopenharmony_ci * sane_start()
1015141cc406Sopenharmony_ci *
1016141cc406Sopenharmony_ci * Starts scanning an image.
1017141cc406Sopenharmony_ci *
1018141cc406Sopenharmony_ci *************************************************************************/
1019141cc406Sopenharmony_ci	SANE_Status
1020141cc406Sopenharmony_cisane_start (SANE_Handle h)
1021141cc406Sopenharmony_ci{
1022141cc406Sopenharmony_ci	unsigned int i, res, max_width, max_height, max_res, tmp;
1023141cc406Sopenharmony_ci	CANONP_Scanner *cs = ((CANONP_Scanner *)h);
1024141cc406Sopenharmony_ci	DBG(2, ">> sane_start (h=%p)\n", h);
1025141cc406Sopenharmony_ci
1026141cc406Sopenharmony_ci	if (h == NULL) return SANE_STATUS_INVAL;
1027141cc406Sopenharmony_ci
1028141cc406Sopenharmony_ci	if (cs->scanning) return SANE_STATUS_DEVICE_BUSY;
1029141cc406Sopenharmony_ci	if (cs->opened == SANE_FALSE)
1030141cc406Sopenharmony_ci	{
1031141cc406Sopenharmony_ci		DBG(1,"sane_start: That scanner (%p) ain't "
1032141cc406Sopenharmony_ci				"open yet\n", h);
1033141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
1034141cc406Sopenharmony_ci	}
1035141cc406Sopenharmony_ci
1036141cc406Sopenharmony_ci
1037141cc406Sopenharmony_ci	/* We use 600 res list here because the 300 res list is just a shorter
1038141cc406Sopenharmony_ci	 * version, so this will always work. */
1039141cc406Sopenharmony_ci	res = res600[cs->vals[OPT_RESOLUTION]];
1040141cc406Sopenharmony_ci
1041141cc406Sopenharmony_ci	/* Copy the options stored in the vals into the scaninfo */
1042141cc406Sopenharmony_ci	cs->scan.width = ((cs->vals[OPT_BR_X] - cs->vals[OPT_TL_X]) * res)
1043141cc406Sopenharmony_ci                / MM_PER_IN;
1044141cc406Sopenharmony_ci	cs->scan.height = ((cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y]) * res)
1045141cc406Sopenharmony_ci                / MM_PER_IN;
1046141cc406Sopenharmony_ci
1047141cc406Sopenharmony_ci	cs->scan.xoffset = (cs->vals[OPT_TL_X] * res) / MM_PER_IN;
1048141cc406Sopenharmony_ci	cs->scan.yoffset = (cs->vals[OPT_TL_Y] * res) / MM_PER_IN;
1049141cc406Sopenharmony_ci
1050141cc406Sopenharmony_ci        /*
1051141cc406Sopenharmony_ci         * These values have to pass the requirements of not exceeding
1052141cc406Sopenharmony_ci         * dimensions (simple clipping) and both width values have to be some
1053141cc406Sopenharmony_ci         * integer multiple of 4
1054141cc406Sopenharmony_ci         */
1055141cc406Sopenharmony_ci
1056141cc406Sopenharmony_ci	/* FIXME: Magic numbers ahead! */
1057141cc406Sopenharmony_ci
1058141cc406Sopenharmony_ci	max_res = cs->params.scanheadwidth == 2552 ? 300 : 600;
1059141cc406Sopenharmony_ci
1060141cc406Sopenharmony_ci	/* x values have to be divisible by 4 (round down) */
1061141cc406Sopenharmony_ci	cs->scan.width -= (cs->scan.width%4);
1062141cc406Sopenharmony_ci	cs->scan.xoffset -= (cs->scan.xoffset%4);
1063141cc406Sopenharmony_ci
1064141cc406Sopenharmony_ci	/* Can't scan less than 64 */
1065141cc406Sopenharmony_ci        if (cs->scan.width < 64) cs->scan.width = 64;
1066141cc406Sopenharmony_ci
1067141cc406Sopenharmony_ci	max_width = cs->params.scanheadwidth / (max_res / res);
1068141cc406Sopenharmony_ci
1069141cc406Sopenharmony_ci	max_height = (cs->params.scanheadwidth == 2552 ? 3508 : 7016) /
1070141cc406Sopenharmony_ci                                        (max_res / res);
1071141cc406Sopenharmony_ci
1072141cc406Sopenharmony_ci        if (cs->scan.width > max_width) cs->scan.width = max_width;
1073141cc406Sopenharmony_ci	if (cs->scan.width + cs->scan.xoffset > max_width) cs->scan.xoffset =
1074141cc406Sopenharmony_ci		max_width - cs->scan.width;
1075141cc406Sopenharmony_ci        if (cs->scan.height > max_height) cs->scan.height = max_height;
1076141cc406Sopenharmony_ci
1077141cc406Sopenharmony_ci	/* We pass a value to init_scan which is the power of 2 that 75
1078141cc406Sopenharmony_ci	 * is multiplied by for the resolution.  ie:
1079141cc406Sopenharmony_ci	 * 75 -> 0
1080141cc406Sopenharmony_ci	 * 150 -> 1
1081141cc406Sopenharmony_ci	 * 300 -> 2
1082141cc406Sopenharmony_ci	 * 600 -> 4
1083141cc406Sopenharmony_ci	 *
1084141cc406Sopenharmony_ci	 * This rather strange parameter is a result of the way the scanner
1085141cc406Sopenharmony_ci	 * takes its resolution argument
1086141cc406Sopenharmony_ci	 */
1087141cc406Sopenharmony_ci
1088141cc406Sopenharmony_ci	i = 0;
1089141cc406Sopenharmony_ci	while (res > 75)
1090141cc406Sopenharmony_ci	{
1091141cc406Sopenharmony_ci		i++;
1092141cc406Sopenharmony_ci		res = res >> 1;
1093141cc406Sopenharmony_ci	}
1094141cc406Sopenharmony_ci
1095141cc406Sopenharmony_ci	/* FIXME? xres == yres for now. */
1096141cc406Sopenharmony_ci	cs->scan.xresolution = i;
1097141cc406Sopenharmony_ci	cs->scan.yresolution = i;
1098141cc406Sopenharmony_ci
1099141cc406Sopenharmony_ci	if (((cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y]) <= 0) ||
1100141cc406Sopenharmony_ci			((cs->vals[OPT_BR_X] - cs->vals[OPT_TL_X]) <= 0))
1101141cc406Sopenharmony_ci	{
1102141cc406Sopenharmony_ci		DBG(1,"sane_start: height = %d, Width = %d. "
1103141cc406Sopenharmony_ci				"Can't scan void range!",
1104141cc406Sopenharmony_ci				cs->scan.height, cs->scan.width);
1105141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
1106141cc406Sopenharmony_ci	}
1107141cc406Sopenharmony_ci
1108141cc406Sopenharmony_ci	cs->scan.mode = cs->vals[OPT_COLOUR_MODE];
1109141cc406Sopenharmony_ci
1110141cc406Sopenharmony_ci	DBG(10, ">> init_scan()\n");
1111141cc406Sopenharmony_ci	tmp = sanei_canon_pp_init_scan(&(cs->params), &(cs->scan));
1112141cc406Sopenharmony_ci	DBG(10, "<< %d init_scan\n", tmp);
1113141cc406Sopenharmony_ci
1114141cc406Sopenharmony_ci	if (tmp != 0) {
1115141cc406Sopenharmony_ci		DBG(1,"sane_start: WARNING: init_scan returned %d!", tmp);
1116141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1117141cc406Sopenharmony_ci	}
1118141cc406Sopenharmony_ci	cs->scanning = SANE_TRUE;
1119141cc406Sopenharmony_ci	cs->cancelled = SANE_FALSE;
1120141cc406Sopenharmony_ci	cs->sent_eof = SANE_FALSE;
1121141cc406Sopenharmony_ci	cs->lines_scanned = 0;
1122141cc406Sopenharmony_ci	cs->bytes_sent = 0;
1123141cc406Sopenharmony_ci
1124141cc406Sopenharmony_ci	DBG(2, "<< sane_start\n");
1125141cc406Sopenharmony_ci
1126141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1127141cc406Sopenharmony_ci}
1128141cc406Sopenharmony_ci
1129141cc406Sopenharmony_ci
1130141cc406Sopenharmony_ci/*************************************************************************
1131141cc406Sopenharmony_ci *
1132141cc406Sopenharmony_ci * sane_read()
1133141cc406Sopenharmony_ci *
1134141cc406Sopenharmony_ci * Reads some information from the buffer.
1135141cc406Sopenharmony_ci *
1136141cc406Sopenharmony_ci *************************************************************************/
1137141cc406Sopenharmony_ci	SANE_Status
1138141cc406Sopenharmony_cisane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp)
1139141cc406Sopenharmony_ci{
1140141cc406Sopenharmony_ci	CANONP_Scanner *cs = ((CANONP_Scanner *)h);
1141141cc406Sopenharmony_ci	image_segment *is;
1142141cc406Sopenharmony_ci	unsigned int lines, bytes, bpl;
1143141cc406Sopenharmony_ci	unsigned int i;
1144141cc406Sopenharmony_ci	short *shortptr;
1145141cc406Sopenharmony_ci	SANE_Byte *charptr;
1146141cc406Sopenharmony_ci	int tmp;
1147141cc406Sopenharmony_ci
1148141cc406Sopenharmony_ci	static SANE_Byte *lbuf;
1149141cc406Sopenharmony_ci	static unsigned int bytesleft;
1150141cc406Sopenharmony_ci
1151141cc406Sopenharmony_ci	DBG(2, ">> sane_read (h=%p, buf=%p, maxlen=%d)\n", h,
1152141cc406Sopenharmony_ci			(const void *)buf, maxlen);
1153141cc406Sopenharmony_ci
1154141cc406Sopenharmony_ci	/* default to returning 0 - for errors */
1155141cc406Sopenharmony_ci	*lenp = 0;
1156141cc406Sopenharmony_ci
1157141cc406Sopenharmony_ci	if ((h == NULL) || (buf == NULL) || (lenp == NULL))
1158141cc406Sopenharmony_ci	{
1159141cc406Sopenharmony_ci		DBG(1, "sane_read: This frontend's passing me dodgy gear! "
1160141cc406Sopenharmony_ci				"(h=%p, buf=%p, lenp=%p)\n",
1161141cc406Sopenharmony_ci				(void*)h, (void*)buf, (void*)lenp);
1162141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
1163141cc406Sopenharmony_ci	}
1164141cc406Sopenharmony_ci
1165141cc406Sopenharmony_ci	/* Now we have to see if we have some leftover from last time */
1166141cc406Sopenharmony_ci
1167141cc406Sopenharmony_ci	if (read_leftover != NULL)
1168141cc406Sopenharmony_ci	{
1169141cc406Sopenharmony_ci		/* feed some more data in until we've run out - don't care
1170141cc406Sopenharmony_ci		 * whether or not we _think_ the scanner is scanning now,
1171141cc406Sopenharmony_ci		 * because we may still have data left over to send */
1172141cc406Sopenharmony_ci		DBG(200, "sane_read: didn't send it all last time\n");
1173141cc406Sopenharmony_ci
1174141cc406Sopenharmony_ci		/* Now feed it some data from lbuf */
1175141cc406Sopenharmony_ci		if (bytesleft <= (unsigned int)maxlen)
1176141cc406Sopenharmony_ci		{
1177141cc406Sopenharmony_ci			/* enough buffer to send the lot */
1178141cc406Sopenharmony_ci			memcpy(buf, read_leftover, bytesleft);
1179141cc406Sopenharmony_ci			free(lbuf);
1180141cc406Sopenharmony_ci			*lenp = bytesleft;
1181141cc406Sopenharmony_ci			lbuf = NULL;
1182141cc406Sopenharmony_ci			read_leftover = NULL;
1183141cc406Sopenharmony_ci			bytesleft = 0;
1184141cc406Sopenharmony_ci                        cs->bytes_sent += bytesleft;
1185141cc406Sopenharmony_ci			return SANE_STATUS_GOOD;
1186141cc406Sopenharmony_ci
1187141cc406Sopenharmony_ci		} else {
1188141cc406Sopenharmony_ci			/* only enough to send maxlen */
1189141cc406Sopenharmony_ci			memcpy(buf, read_leftover, maxlen);
1190141cc406Sopenharmony_ci			read_leftover += maxlen;
1191141cc406Sopenharmony_ci			bytesleft -= maxlen;
1192141cc406Sopenharmony_ci			*lenp = maxlen;
1193141cc406Sopenharmony_ci                        cs->bytes_sent += maxlen;
1194141cc406Sopenharmony_ci		        DBG(100, "sane_read: sent %d bytes, still have %d to "
1195141cc406Sopenharmony_ci                                "go\n", maxlen, bytesleft);
1196141cc406Sopenharmony_ci			return SANE_STATUS_GOOD;
1197141cc406Sopenharmony_ci		}
1198141cc406Sopenharmony_ci
1199141cc406Sopenharmony_ci	}
1200141cc406Sopenharmony_ci
1201141cc406Sopenharmony_ci
1202141cc406Sopenharmony_ci	/* Has the last scan ended (other than by cancelling)? */
1203141cc406Sopenharmony_ci	if (((unsigned)cs->scan.height <= (unsigned)cs->lines_scanned)
1204141cc406Sopenharmony_ci	    || (cs->sent_eof) || !(cs->scanning))
1205141cc406Sopenharmony_ci	{
1206141cc406Sopenharmony_ci		cs->sent_eof = SANE_TRUE;
1207141cc406Sopenharmony_ci		cs->scanning = SANE_FALSE;
1208141cc406Sopenharmony_ci		cs->cancelled = SANE_FALSE;
1209141cc406Sopenharmony_ci		cs->lines_scanned = 0;
1210141cc406Sopenharmony_ci		cs->bytes_sent = 0;
1211141cc406Sopenharmony_ci		read_leftover = NULL;
1212141cc406Sopenharmony_ci		return SANE_STATUS_EOF;
1213141cc406Sopenharmony_ci	}
1214141cc406Sopenharmony_ci
1215141cc406Sopenharmony_ci	/* At this point we have to read more data from the scanner - or the
1216141cc406Sopenharmony_ci	 * scan has been cancelled, which means we have to call read_segment
1217141cc406Sopenharmony_ci	 * to leave the scanner consistent */
1218141cc406Sopenharmony_ci
1219141cc406Sopenharmony_ci	/* Decide how many lines we can fit into this buffer */
1220141cc406Sopenharmony_ci	if (cs->vals[OPT_DEPTH] == 0)
1221141cc406Sopenharmony_ci		bpl = cs->scan.width * (cs->vals[OPT_COLOUR_MODE] ? 3 : 1);
1222141cc406Sopenharmony_ci	else
1223141cc406Sopenharmony_ci		bpl = cs->scan.width * (cs->vals[OPT_COLOUR_MODE] ? 6 : 2);
1224141cc406Sopenharmony_ci
1225141cc406Sopenharmony_ci        /* New way: scan a whole scanner buffer full, and return as much as
1226141cc406Sopenharmony_ci         * the frontend wants.  It's faster and more reliable since the
1227141cc406Sopenharmony_ci         * scanners crack the shits if we ask for too many small packets */
1228141cc406Sopenharmony_ci	lines = (BUF_MAX * 4 / 5) / bpl;
1229141cc406Sopenharmony_ci
1230141cc406Sopenharmony_ci	if (lines > (cs->scan.height - cs->lines_scanned))
1231141cc406Sopenharmony_ci		lines = cs->scan.height - cs->lines_scanned;
1232141cc406Sopenharmony_ci
1233141cc406Sopenharmony_ci	if (!lines)
1234141cc406Sopenharmony_ci	{
1235141cc406Sopenharmony_ci		/* can't fit a whole line into the buffer
1236141cc406Sopenharmony_ci                 * (should never happen!) */
1237141cc406Sopenharmony_ci		lines = 1;
1238141cc406Sopenharmony_ci	}
1239141cc406Sopenharmony_ci
1240141cc406Sopenharmony_ci	bytes = lines * bpl;
1241141cc406Sopenharmony_ci
1242141cc406Sopenharmony_ci	/* Allocate a local buffer to hold the data while we play */
1243141cc406Sopenharmony_ci	if ((lbuf = malloc(bytes)) == NULL)
1244141cc406Sopenharmony_ci	{
1245141cc406Sopenharmony_ci		DBG(10, "sane_read: Not enough memory to hold a "
1246141cc406Sopenharmony_ci				"local buffer.  You're doomed\n");
1247141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
1248141cc406Sopenharmony_ci	}
1249141cc406Sopenharmony_ci
1250141cc406Sopenharmony_ci
1251141cc406Sopenharmony_ci	/* This call required a lot of debugging information.. */
1252141cc406Sopenharmony_ci	DBG(10, "sane_read: Here's what we're sending read_segment:\n");
1253141cc406Sopenharmony_ci	DBG(10, "scanner setup: shw=%d xres=%d yres=%d %d %d id=%s\n",
1254141cc406Sopenharmony_ci			cs->params.scanheadwidth,
1255141cc406Sopenharmony_ci			cs->params.natural_xresolution,
1256141cc406Sopenharmony_ci			cs->params.natural_yresolution,
1257141cc406Sopenharmony_ci			cs->params.max_xresolution,
1258141cc406Sopenharmony_ci			cs->params.max_yresolution,
1259141cc406Sopenharmony_ci			(cs->params.id_string)+8);
1260141cc406Sopenharmony_ci	DBG(10, "scan_params->: width=%d, height=%d, xoffset=%d, "
1261141cc406Sopenharmony_ci			"yoffset=%d\n\txresolution=%d, yresolution=%d, "
1262141cc406Sopenharmony_ci			"mode=%d, (lines=%d)\n",
1263141cc406Sopenharmony_ci			cs->scan.width, cs->scan.height,
1264141cc406Sopenharmony_ci			cs->scan.xoffset, cs->scan.yoffset,
1265141cc406Sopenharmony_ci			cs->scan.xresolution, cs->scan.yresolution,
1266141cc406Sopenharmony_ci			cs->scan.mode, lines);
1267141cc406Sopenharmony_ci
1268141cc406Sopenharmony_ci	DBG(2, ">> read_segment(x, x, x, %d, %d, %d)\n",
1269141cc406Sopenharmony_ci			lines, cs->cal_valid,
1270141cc406Sopenharmony_ci			cs->scan.height - cs->lines_scanned);
1271141cc406Sopenharmony_ci	tmp = sanei_canon_pp_read_segment(&is, &(cs->params), &(cs->scan),
1272141cc406Sopenharmony_ci			lines, cs->cal_valid,
1273141cc406Sopenharmony_ci			cs->scan.height - cs->lines_scanned);
1274141cc406Sopenharmony_ci	DBG(2, "<< %d read_segment\n", tmp);
1275141cc406Sopenharmony_ci
1276141cc406Sopenharmony_ci	if (tmp != 0) {
1277141cc406Sopenharmony_ci		if (cs->cancelled)
1278141cc406Sopenharmony_ci		{
1279141cc406Sopenharmony_ci			DBG(10, "sane_read: cancelling.\n");
1280141cc406Sopenharmony_ci			cs->sent_eof = SANE_TRUE;
1281141cc406Sopenharmony_ci			cs->scanning = SANE_FALSE;
1282141cc406Sopenharmony_ci			read_leftover = NULL;
1283141cc406Sopenharmony_ci			sanei_canon_pp_abort_scan(&(cs->params));
1284141cc406Sopenharmony_ci			return SANE_STATUS_CANCELLED;
1285141cc406Sopenharmony_ci		}
1286141cc406Sopenharmony_ci		DBG(1, "sane_read: WARNING: read_segment returned %d!\n", tmp);
1287141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1288141cc406Sopenharmony_ci	}
1289141cc406Sopenharmony_ci
1290141cc406Sopenharmony_ci	DBG(10, "sane_read: bpl=%d, lines=%d, bytes=%d\n", bpl, lines, bytes);
1291141cc406Sopenharmony_ci
1292141cc406Sopenharmony_ci	cs->lines_scanned += lines;
1293141cc406Sopenharmony_ci
1294141cc406Sopenharmony_ci	/* translate data out of buffer */
1295141cc406Sopenharmony_ci	if (cs->vals[OPT_DEPTH] == 0)
1296141cc406Sopenharmony_ci	{
1297141cc406Sopenharmony_ci		/* 8bpp */
1298141cc406Sopenharmony_ci		for(i = 0; i < bytes; i++)
1299141cc406Sopenharmony_ci		{
1300141cc406Sopenharmony_ci			charptr = lbuf + i;
1301141cc406Sopenharmony_ci			if (cs->vals[OPT_COLOUR_MODE])
1302141cc406Sopenharmony_ci			{
1303141cc406Sopenharmony_ci				if (i % 3 == 0) charptr += 2;
1304141cc406Sopenharmony_ci				if (i % 3 == 2) charptr -= 2;
1305141cc406Sopenharmony_ci			}
1306141cc406Sopenharmony_ci			*charptr = *((char *)(is->image_data) + (i*2));
1307141cc406Sopenharmony_ci		}
1308141cc406Sopenharmony_ci	}
1309141cc406Sopenharmony_ci	else
1310141cc406Sopenharmony_ci	{
1311141cc406Sopenharmony_ci		/* 16bpp */
1312141cc406Sopenharmony_ci		for(i = 0; i < (bytes/2); i++)
1313141cc406Sopenharmony_ci		{
1314141cc406Sopenharmony_ci			shortptr = ((short *)lbuf + i);
1315141cc406Sopenharmony_ci			if (cs->vals[OPT_COLOUR_MODE])
1316141cc406Sopenharmony_ci			{
1317141cc406Sopenharmony_ci				if (i % 3 == 0) shortptr += 2;
1318141cc406Sopenharmony_ci				if (i % 3 == 2) shortptr -= 2;
1319141cc406Sopenharmony_ci			}
1320141cc406Sopenharmony_ci			*shortptr = MAKE_SHORT(
1321141cc406Sopenharmony_ci					*((char *)(is->image_data) + (i*2)),
1322141cc406Sopenharmony_ci					*((char *)(is->image_data) + (i*2)+1)
1323141cc406Sopenharmony_ci					);
1324141cc406Sopenharmony_ci		}
1325141cc406Sopenharmony_ci	}
1326141cc406Sopenharmony_ci
1327141cc406Sopenharmony_ci	/* Free data structures allocated in read_segment */
1328141cc406Sopenharmony_ci	free(is->image_data);
1329141cc406Sopenharmony_ci	free(is);
1330141cc406Sopenharmony_ci
1331141cc406Sopenharmony_ci	/* Now feed it some data from lbuf */
1332141cc406Sopenharmony_ci	if (bytes <= (unsigned int)maxlen)
1333141cc406Sopenharmony_ci	{
1334141cc406Sopenharmony_ci		/* enough buffer to send the lot */
1335141cc406Sopenharmony_ci		memcpy(buf, lbuf, bytes);
1336141cc406Sopenharmony_ci		*lenp = bytes;
1337141cc406Sopenharmony_ci		free(lbuf);
1338141cc406Sopenharmony_ci		lbuf = NULL;
1339141cc406Sopenharmony_ci		read_leftover = NULL;
1340141cc406Sopenharmony_ci		bytesleft = 0;
1341141cc406Sopenharmony_ci                cs->bytes_sent += bytes;
1342141cc406Sopenharmony_ci
1343141cc406Sopenharmony_ci	} else {
1344141cc406Sopenharmony_ci		/* only enough to send maxlen */
1345141cc406Sopenharmony_ci		memcpy(buf, lbuf, maxlen);
1346141cc406Sopenharmony_ci		*lenp = maxlen;
1347141cc406Sopenharmony_ci		read_leftover = lbuf + maxlen;
1348141cc406Sopenharmony_ci		bytesleft = bytes - maxlen;
1349141cc406Sopenharmony_ci                cs->bytes_sent += maxlen;
1350141cc406Sopenharmony_ci		DBG(100, "sane_read: sent %d bytes, still have %d to go\n",
1351141cc406Sopenharmony_ci                        maxlen, bytesleft);
1352141cc406Sopenharmony_ci	}
1353141cc406Sopenharmony_ci
1354141cc406Sopenharmony_ci	if ((unsigned)cs->lines_scanned >= cs->scan.height)
1355141cc406Sopenharmony_ci	{
1356141cc406Sopenharmony_ci		/* The scan is over! Don't need to call anything in the
1357141cc406Sopenharmony_ci		 * hardware, it will sort itself out */
1358141cc406Sopenharmony_ci		DBG(10, "sane_read: Scan is finished.\n");
1359141cc406Sopenharmony_ci		cs->scanning = SANE_FALSE;
1360141cc406Sopenharmony_ci		cs->lines_scanned = 0;
1361141cc406Sopenharmony_ci		cs->bytes_sent = 0;
1362141cc406Sopenharmony_ci	}
1363141cc406Sopenharmony_ci
1364141cc406Sopenharmony_ci	DBG(2, "<< sane_read\n");
1365141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1366141cc406Sopenharmony_ci}
1367141cc406Sopenharmony_ci
1368141cc406Sopenharmony_ci
1369141cc406Sopenharmony_ci/*************************************************************************
1370141cc406Sopenharmony_ci *
1371141cc406Sopenharmony_ci * sane_cancel()
1372141cc406Sopenharmony_ci *
1373141cc406Sopenharmony_ci * Cancels a scan in progress
1374141cc406Sopenharmony_ci *
1375141cc406Sopenharmony_ci *************************************************************************/
1376141cc406Sopenharmony_ci	void
1377141cc406Sopenharmony_cisane_cancel (SANE_Handle h)
1378141cc406Sopenharmony_ci{
1379141cc406Sopenharmony_ci	/* Note: assume handle is valid apart from NULLs */
1380141cc406Sopenharmony_ci	CANONP_Scanner *cs = ((CANONP_Scanner *)h);
1381141cc406Sopenharmony_ci
1382141cc406Sopenharmony_ci	DBG(2, ">> sane_cancel (h=%p)\n", h);
1383141cc406Sopenharmony_ci	if (h == NULL) return;
1384141cc406Sopenharmony_ci
1385141cc406Sopenharmony_ci	read_leftover = NULL;
1386141cc406Sopenharmony_ci
1387141cc406Sopenharmony_ci	if (!(cs->scanning))
1388141cc406Sopenharmony_ci	{
1389141cc406Sopenharmony_ci		DBG(2, "<< sane_cancel (not scanning)\n");
1390141cc406Sopenharmony_ci		return;
1391141cc406Sopenharmony_ci	}
1392141cc406Sopenharmony_ci
1393141cc406Sopenharmony_ci	cs->cancelled = SANE_TRUE;
1394141cc406Sopenharmony_ci	cs->params.abort_now = 1;
1395141cc406Sopenharmony_ci
1396141cc406Sopenharmony_ci	DBG(2, "<< sane_cancel\n");
1397141cc406Sopenharmony_ci}
1398141cc406Sopenharmony_ci
1399141cc406Sopenharmony_ci
1400141cc406Sopenharmony_ci/*************************************************************************
1401141cc406Sopenharmony_ci *
1402141cc406Sopenharmony_ci * sane_close()
1403141cc406Sopenharmony_ci *
1404141cc406Sopenharmony_ci * Closes a scanner handle.  Scanner is assumed to be free after this.
1405141cc406Sopenharmony_ci *
1406141cc406Sopenharmony_ci *************************************************************************/
1407141cc406Sopenharmony_ci	void
1408141cc406Sopenharmony_cisane_close (SANE_Handle h)
1409141cc406Sopenharmony_ci{
1410141cc406Sopenharmony_ci	/* Note: assume handle is valid apart from NULLs */
1411141cc406Sopenharmony_ci	CANONP_Scanner *cs = ((CANONP_Scanner *)h);
1412141cc406Sopenharmony_ci	DBG(2, ">> sane_close (h=%p)\n", h);
1413141cc406Sopenharmony_ci	if (h == NULL) return;
1414141cc406Sopenharmony_ci
1415141cc406Sopenharmony_ci	if (cs->opened == SANE_FALSE)
1416141cc406Sopenharmony_ci	{
1417141cc406Sopenharmony_ci		DBG(1,"sane_close: That scanner (%p) ain't "
1418141cc406Sopenharmony_ci				"open yet\n", h);
1419141cc406Sopenharmony_ci		return;
1420141cc406Sopenharmony_ci	}
1421141cc406Sopenharmony_ci
1422141cc406Sopenharmony_ci	/* Put scanner back in transparent mode */
1423141cc406Sopenharmony_ci	sanei_canon_pp_close_scanner(&(cs->params));
1424141cc406Sopenharmony_ci
1425141cc406Sopenharmony_ci	cs->opened = SANE_FALSE;
1426141cc406Sopenharmony_ci
1427141cc406Sopenharmony_ci	/* if it was scanning, it's not any more */
1428141cc406Sopenharmony_ci	cs->scanning = SANE_FALSE;
1429141cc406Sopenharmony_ci	cs->sent_eof = SANE_TRUE;
1430141cc406Sopenharmony_ci
1431141cc406Sopenharmony_ci	ieee1284_release(cs->params.port);
1432141cc406Sopenharmony_ci
1433141cc406Sopenharmony_ci	DBG(2, "<< sane_close\n");
1434141cc406Sopenharmony_ci}
1435141cc406Sopenharmony_ci
1436141cc406Sopenharmony_ci
1437141cc406Sopenharmony_ci/*************************************************************************
1438141cc406Sopenharmony_ci *
1439141cc406Sopenharmony_ci * sane_exit()
1440141cc406Sopenharmony_ci *
1441141cc406Sopenharmony_ci * Shut it down!
1442141cc406Sopenharmony_ci *
1443141cc406Sopenharmony_ci *************************************************************************/
1444141cc406Sopenharmony_ci	void
1445141cc406Sopenharmony_cisane_exit (void)
1446141cc406Sopenharmony_ci{
1447141cc406Sopenharmony_ci	CANONP_Scanner *dev, *next;
1448141cc406Sopenharmony_ci
1449141cc406Sopenharmony_ci	DBG(2, ">> sane_exit\n");
1450141cc406Sopenharmony_ci
1451141cc406Sopenharmony_ci	for (dev = first_dev; dev != NULL; dev = next)
1452141cc406Sopenharmony_ci	{
1453141cc406Sopenharmony_ci		next = dev->next;
1454141cc406Sopenharmony_ci
1455141cc406Sopenharmony_ci		/* These were only created if the scanner has been init'd */
1456141cc406Sopenharmony_ci
1457141cc406Sopenharmony_ci		/* Should normally nullify pointers after freeing, but in
1458141cc406Sopenharmony_ci		 * this case we're about to free the whole structure so
1459141cc406Sopenharmony_ci		 * there's not a lot of point. */
1460141cc406Sopenharmony_ci
1461141cc406Sopenharmony_ci		/* Constraints (mostly) allocated when the scanner is opened */
1462141cc406Sopenharmony_ci		if(dev->opt[OPT_TL_X].constraint.range)
1463141cc406Sopenharmony_ci			free((void *)(dev->opt[OPT_TL_X].constraint.range));
1464141cc406Sopenharmony_ci		if(dev->opt[OPT_TL_Y].constraint.range)
1465141cc406Sopenharmony_ci			free((void *)(dev->opt[OPT_TL_Y].constraint.range));
1466141cc406Sopenharmony_ci		if(dev->opt[OPT_BR_X].constraint.range)
1467141cc406Sopenharmony_ci			free((void *)(dev->opt[OPT_BR_X].constraint.range));
1468141cc406Sopenharmony_ci		if(dev->opt[OPT_BR_Y].constraint.range)
1469141cc406Sopenharmony_ci			free((void *)(dev->opt[OPT_BR_Y].constraint.range));
1470141cc406Sopenharmony_ci
1471141cc406Sopenharmony_ci		/* Weights file now on a per-scanner basis */
1472141cc406Sopenharmony_ci		if (dev->weights_file != NULL)
1473141cc406Sopenharmony_ci			free(dev->weights_file);
1474141cc406Sopenharmony_ci
1475141cc406Sopenharmony_ci		if (dev->scanner_present)
1476141cc406Sopenharmony_ci		{
1477141cc406Sopenharmony_ci			if (dev->opened == SANE_TRUE)
1478141cc406Sopenharmony_ci			{
1479141cc406Sopenharmony_ci				/* naughty boys, should have closed first */
1480141cc406Sopenharmony_ci				ieee1284_release(dev->params.port);
1481141cc406Sopenharmony_ci			}
1482141cc406Sopenharmony_ci			ieee1284_close(dev->params.port);
1483141cc406Sopenharmony_ci		}
1484141cc406Sopenharmony_ci
1485141cc406Sopenharmony_ci		free (dev);
1486141cc406Sopenharmony_ci	}
1487141cc406Sopenharmony_ci
1488141cc406Sopenharmony_ci	first_dev = NULL;
1489141cc406Sopenharmony_ci	def_scanner = NULL;
1490141cc406Sopenharmony_ci	read_leftover = NULL;
1491141cc406Sopenharmony_ci	num_devices = 0;
1492141cc406Sopenharmony_ci
1493141cc406Sopenharmony_ci	/* FIXEDME: this created a segfault in DLL code. */
1494141cc406Sopenharmony_ci	/* Bug was fixed in libieee1284 0.1.5 */
1495141cc406Sopenharmony_ci	ieee1284_free_ports(&pl);
1496141cc406Sopenharmony_ci
1497141cc406Sopenharmony_ci	DBG(2, "<< sane_exit\n");
1498141cc406Sopenharmony_ci}
1499141cc406Sopenharmony_ci
1500141cc406Sopenharmony_ci
1501141cc406Sopenharmony_ci/*************************************************************************
1502141cc406Sopenharmony_ci *
1503141cc406Sopenharmony_ci * init_device()
1504141cc406Sopenharmony_ci *
1505141cc406Sopenharmony_ci * (Not part of the SANE API)
1506141cc406Sopenharmony_ci *
1507141cc406Sopenharmony_ci * Initialises a CANONP_Scanner data structure for a new device.
1508141cc406Sopenharmony_ci * NOTE: The device is not ready to scan until initialise() has been
1509141cc406Sopenharmony_ci * called in scan library!
1510141cc406Sopenharmony_ci *
1511141cc406Sopenharmony_ci *************************************************************************/
1512141cc406Sopenharmony_cistatic SANE_Status init_device(struct parport *pp)
1513141cc406Sopenharmony_ci{
1514141cc406Sopenharmony_ci	int i;
1515141cc406Sopenharmony_ci	static const char *hw_vendor = "CANON";
1516141cc406Sopenharmony_ci	static const char *hw_type = "flatbed scanner";
1517141cc406Sopenharmony_ci	static const char *opt_names[] = {
1518141cc406Sopenharmony_ci		SANE_NAME_NUM_OPTIONS,
1519141cc406Sopenharmony_ci		SANE_NAME_SCAN_RESOLUTION,
1520141cc406Sopenharmony_ci		SANE_NAME_SCAN_MODE,
1521141cc406Sopenharmony_ci		SANE_NAME_BIT_DEPTH,
1522141cc406Sopenharmony_ci		SANE_NAME_SCAN_TL_X,
1523141cc406Sopenharmony_ci		SANE_NAME_SCAN_TL_Y,
1524141cc406Sopenharmony_ci		SANE_NAME_SCAN_BR_X,
1525141cc406Sopenharmony_ci		SANE_NAME_SCAN_BR_Y,
1526141cc406Sopenharmony_ci		SANE_NAME_QUALITY_CAL
1527141cc406Sopenharmony_ci#if 0
1528141cc406Sopenharmony_ci		SANE_NAME_GAMMA_R,
1529141cc406Sopenharmony_ci		SANE_NAME_GAMMA_G,
1530141cc406Sopenharmony_ci		SANE_NAME_GAMMA_B
1531141cc406Sopenharmony_ci#endif
1532141cc406Sopenharmony_ci	};
1533141cc406Sopenharmony_ci	static const char *opt_titles[] = {
1534141cc406Sopenharmony_ci		SANE_TITLE_NUM_OPTIONS,
1535141cc406Sopenharmony_ci		SANE_TITLE_SCAN_RESOLUTION,
1536141cc406Sopenharmony_ci		SANE_TITLE_SCAN_MODE,
1537141cc406Sopenharmony_ci		SANE_TITLE_BIT_DEPTH,
1538141cc406Sopenharmony_ci		SANE_TITLE_SCAN_TL_X,
1539141cc406Sopenharmony_ci		SANE_TITLE_SCAN_TL_Y,
1540141cc406Sopenharmony_ci		SANE_TITLE_SCAN_BR_X,
1541141cc406Sopenharmony_ci		SANE_TITLE_SCAN_BR_Y,
1542141cc406Sopenharmony_ci		SANE_TITLE_QUALITY_CAL
1543141cc406Sopenharmony_ci#if 0
1544141cc406Sopenharmony_ci		SANE_TITLE_GAMMA_R,
1545141cc406Sopenharmony_ci		SANE_TITLE_GAMMA_G,
1546141cc406Sopenharmony_ci		SANE_TITLE_GAMMA_B
1547141cc406Sopenharmony_ci#endif
1548141cc406Sopenharmony_ci	};
1549141cc406Sopenharmony_ci	static const char *opt_descs[] = {
1550141cc406Sopenharmony_ci		SANE_DESC_NUM_OPTIONS,
1551141cc406Sopenharmony_ci		SANE_DESC_SCAN_RESOLUTION,
1552141cc406Sopenharmony_ci		SANE_DESC_SCAN_MODE,
1553141cc406Sopenharmony_ci		SANE_DESC_BIT_DEPTH,
1554141cc406Sopenharmony_ci		SANE_DESC_SCAN_TL_X,
1555141cc406Sopenharmony_ci		SANE_DESC_SCAN_TL_Y,
1556141cc406Sopenharmony_ci		SANE_DESC_SCAN_BR_X,
1557141cc406Sopenharmony_ci		SANE_DESC_SCAN_BR_Y,
1558141cc406Sopenharmony_ci		SANE_DESC_QUALITY_CAL
1559141cc406Sopenharmony_ci#if 0
1560141cc406Sopenharmony_ci		SANE_DESC_GAMMA_R,
1561141cc406Sopenharmony_ci		SANE_DESC_GAMMA_G,
1562141cc406Sopenharmony_ci		SANE_DESC_GAMMA_B
1563141cc406Sopenharmony_ci#endif
1564141cc406Sopenharmony_ci	};
1565141cc406Sopenharmony_ci
1566141cc406Sopenharmony_ci	CANONP_Scanner *cs = NULL;
1567141cc406Sopenharmony_ci
1568141cc406Sopenharmony_ci	DBG(2, ">> init_device\n");
1569141cc406Sopenharmony_ci
1570141cc406Sopenharmony_ci	cs = malloc(sizeof(*cs));
1571141cc406Sopenharmony_ci	if (cs == NULL)
1572141cc406Sopenharmony_ci	{
1573141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
1574141cc406Sopenharmony_ci	}
1575141cc406Sopenharmony_ci	memset(cs, 0, sizeof(*cs));
1576141cc406Sopenharmony_ci
1577141cc406Sopenharmony_ci#if 0
1578141cc406Sopenharmony_ci	if ((cs->params.port = malloc(sizeof(*(cs->params.port)))) == NULL)
1579141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
1580141cc406Sopenharmony_ci
1581141cc406Sopenharmony_ci	memcpy(cs->params.port, pp, sizeof(*pp));
1582141cc406Sopenharmony_ci#endif
1583141cc406Sopenharmony_ci
1584141cc406Sopenharmony_ci	cs->params.port = pp;
1585141cc406Sopenharmony_ci
1586141cc406Sopenharmony_ci	/* ensure these are null to start off with, otherwise they might be
1587141cc406Sopenharmony_ci	 * erroneously free'd.  Note that we set everything to 0 above
1588141cc406Sopenharmony_ci	 * but that's not *always* the same thing */
1589141cc406Sopenharmony_ci	cs->params.blackweight = NULL;
1590141cc406Sopenharmony_ci	cs->params.redweight = NULL;
1591141cc406Sopenharmony_ci	cs->params.greenweight = NULL;
1592141cc406Sopenharmony_ci	cs->params.blueweight = NULL;
1593141cc406Sopenharmony_ci
1594141cc406Sopenharmony_ci	/* Set some sensible defaults */
1595141cc406Sopenharmony_ci	cs->hw.name = cs->params.port->name;
1596141cc406Sopenharmony_ci	cs->hw.vendor = hw_vendor;
1597141cc406Sopenharmony_ci	cs->hw.type = hw_type;
1598141cc406Sopenharmony_ci	cs->opened = SANE_FALSE;
1599141cc406Sopenharmony_ci	cs->scanning = SANE_FALSE;
1600141cc406Sopenharmony_ci	cs->cancelled = SANE_FALSE;
1601141cc406Sopenharmony_ci	cs->sent_eof = SANE_TRUE;
1602141cc406Sopenharmony_ci	cs->lines_scanned = 0;
1603141cc406Sopenharmony_ci	cs->bytes_sent = 0;
1604141cc406Sopenharmony_ci	cs->init_mode = INITMODE_AUTO;
1605141cc406Sopenharmony_ci
1606141cc406Sopenharmony_ci	DBG(10, "init_device: [configuring options]\n");
1607141cc406Sopenharmony_ci
1608141cc406Sopenharmony_ci	/* take a punt at each option, then we change it later */
1609141cc406Sopenharmony_ci	for (i = 0; i < NUM_OPTIONS; i++)
1610141cc406Sopenharmony_ci	{
1611141cc406Sopenharmony_ci		cs->opt[i].name = opt_names[i];
1612141cc406Sopenharmony_ci		cs->opt[i].title = opt_titles[i];
1613141cc406Sopenharmony_ci		cs->opt[i].desc = opt_descs[i];
1614141cc406Sopenharmony_ci		cs->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1615141cc406Sopenharmony_ci		cs->opt[i].type = SANE_TYPE_INT;
1616141cc406Sopenharmony_ci		cs->opt[i].size = sizeof(SANE_Int);
1617141cc406Sopenharmony_ci	}
1618141cc406Sopenharmony_ci
1619141cc406Sopenharmony_ci	DBG(100, "init_device: configuring opt: num_options\n");
1620141cc406Sopenharmony_ci	/* The number of options option */
1621141cc406Sopenharmony_ci
1622141cc406Sopenharmony_ci	cs->opt[OPT_NUM_OPTIONS].unit = SANE_UNIT_NONE;
1623141cc406Sopenharmony_ci	cs->opt[OPT_NUM_OPTIONS].cap = SANE_CAP_SOFT_DETECT;
1624141cc406Sopenharmony_ci	cs->vals[OPT_NUM_OPTIONS] = NUM_OPTIONS;
1625141cc406Sopenharmony_ci
1626141cc406Sopenharmony_ci	DBG(100, "init_device: configuring opt: resolution\n");
1627141cc406Sopenharmony_ci
1628141cc406Sopenharmony_ci	/* The resolution of scanning (X res == Y res for now)*/
1629141cc406Sopenharmony_ci	cs->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
1630141cc406Sopenharmony_ci	cs->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
1631141cc406Sopenharmony_ci	/* should never point at first element (wordlist size) */
1632141cc406Sopenharmony_ci	cs->vals[OPT_RESOLUTION] = 1;
1633141cc406Sopenharmony_ci
1634141cc406Sopenharmony_ci	DBG(100, "init_device: configuring opt: colour mode\n");
1635141cc406Sopenharmony_ci
1636141cc406Sopenharmony_ci	/* The colour mode (0=grey 1=rgb) */
1637141cc406Sopenharmony_ci	cs->opt[OPT_COLOUR_MODE].type = SANE_TYPE_STRING;
1638141cc406Sopenharmony_ci	cs->opt[OPT_COLOUR_MODE].size = 20;
1639141cc406Sopenharmony_ci	cs->opt[OPT_COLOUR_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1640141cc406Sopenharmony_ci	/* Set this one here because it doesn't change by scanner (yet) */
1641141cc406Sopenharmony_ci	cs->opt[OPT_COLOUR_MODE].constraint.string_list = cmodes;
1642141cc406Sopenharmony_ci
1643141cc406Sopenharmony_ci	DBG(100, "init_device: configuring opt: bit depth\n");
1644141cc406Sopenharmony_ci
1645141cc406Sopenharmony_ci	/* The bit depth */
1646141cc406Sopenharmony_ci	cs->opt[OPT_DEPTH].type = SANE_TYPE_STRING;
1647141cc406Sopenharmony_ci	cs->opt[OPT_DEPTH].size = 20;
1648141cc406Sopenharmony_ci	cs->opt[OPT_DEPTH].cap |= SANE_CAP_EMULATED;
1649141cc406Sopenharmony_ci	cs->opt[OPT_DEPTH].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1650141cc406Sopenharmony_ci	cs->opt[OPT_DEPTH].constraint.string_list = depths;
1651141cc406Sopenharmony_ci
1652141cc406Sopenharmony_ci	DBG(100, "init_device: configuring opt: tl-x\n");
1653141cc406Sopenharmony_ci
1654141cc406Sopenharmony_ci	/* The top-left-x */
1655141cc406Sopenharmony_ci	cs->opt[OPT_TL_X].unit = SANE_UNIT_MM;
1656141cc406Sopenharmony_ci	cs->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
1657141cc406Sopenharmony_ci
1658141cc406Sopenharmony_ci	DBG(100, "init_device: configuring opt: tl-y\n");
1659141cc406Sopenharmony_ci
1660141cc406Sopenharmony_ci	/* The top-left-y */
1661141cc406Sopenharmony_ci	cs->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
1662141cc406Sopenharmony_ci	cs->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1663141cc406Sopenharmony_ci
1664141cc406Sopenharmony_ci	DBG(100, "init_device: configuring opt: br-x\n");
1665141cc406Sopenharmony_ci
1666141cc406Sopenharmony_ci	/* The bottom-right-x */
1667141cc406Sopenharmony_ci	cs->opt[OPT_BR_X].unit = SANE_UNIT_MM;
1668141cc406Sopenharmony_ci	cs->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
1669141cc406Sopenharmony_ci	/* default scan width */
1670141cc406Sopenharmony_ci	cs->vals[OPT_BR_X] = 100;
1671141cc406Sopenharmony_ci
1672141cc406Sopenharmony_ci	DBG(100, "init_device: configuring opt: br-y\n");
1673141cc406Sopenharmony_ci
1674141cc406Sopenharmony_ci	/* The bottom-right-y */
1675141cc406Sopenharmony_ci	cs->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
1676141cc406Sopenharmony_ci	cs->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1677141cc406Sopenharmony_ci	cs->vals[OPT_BR_Y] = 100;
1678141cc406Sopenharmony_ci
1679141cc406Sopenharmony_ci	DBG(100, "init_device: configuring opt: calibrate\n");
1680141cc406Sopenharmony_ci
1681141cc406Sopenharmony_ci	/* The calibration button */
1682141cc406Sopenharmony_ci	cs->opt[OPT_CAL].type = SANE_TYPE_BUTTON;
1683141cc406Sopenharmony_ci	cs->opt[OPT_CAL].constraint_type = SANE_CONSTRAINT_NONE;
1684141cc406Sopenharmony_ci	if (cs->cal_readonly)
1685141cc406Sopenharmony_ci		cs->opt[OPT_CAL].cap |= SANE_CAP_INACTIVE;
1686141cc406Sopenharmony_ci
1687141cc406Sopenharmony_ci#if 0
1688141cc406Sopenharmony_ci	/* the gamma values (once we do them) */
1689141cc406Sopenharmony_ci	cs->opt[OPT_GAMMA_R].caps |= SANE_CAP_ADVANCED;
1690141cc406Sopenharmony_ci	cs->opt[OPT_GAMMA_G].caps |= SANE_CAP_ADVANCED;
1691141cc406Sopenharmony_ci	cs->opt[OPT_GAMMA_B].caps |= SANE_CAP_ADVANCED;
1692141cc406Sopenharmony_ci#endif
1693141cc406Sopenharmony_ci
1694141cc406Sopenharmony_ci	/*
1695141cc406Sopenharmony_ci	 * NOTE: Ranges and lists are actually set when scanner is opened,
1696141cc406Sopenharmony_ci	 * because that's when we find out what sort of scanner it is
1697141cc406Sopenharmony_ci	 */
1698141cc406Sopenharmony_ci
1699141cc406Sopenharmony_ci	DBG(100, "init_device: done opts\n");
1700141cc406Sopenharmony_ci
1701141cc406Sopenharmony_ci	/* add it to the head of the tree */
1702141cc406Sopenharmony_ci	cs->next = first_dev;
1703141cc406Sopenharmony_ci	first_dev = cs;
1704141cc406Sopenharmony_ci
1705141cc406Sopenharmony_ci	num_devices++;
1706141cc406Sopenharmony_ci
1707141cc406Sopenharmony_ci	DBG(2, "<< init_device\n");
1708141cc406Sopenharmony_ci
1709141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1710141cc406Sopenharmony_ci}
1711141cc406Sopenharmony_ci
1712141cc406Sopenharmony_ci
1713141cc406Sopenharmony_ci/*************************************************************************
1714141cc406Sopenharmony_ci *
1715141cc406Sopenharmony_ci * These two are optional ones... maybe if I get really keen?
1716141cc406Sopenharmony_ci *
1717141cc406Sopenharmony_ci *************************************************************************/
1718141cc406Sopenharmony_ci	SANE_Status
1719141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle h, SANE_Bool non_blocking)
1720141cc406Sopenharmony_ci{
1721141cc406Sopenharmony_ci	DBG(2, ">> sane_set_io_mode (%p, %d) (not really supported)\n",
1722141cc406Sopenharmony_ci			h, non_blocking);
1723141cc406Sopenharmony_ci
1724141cc406Sopenharmony_ci	if (non_blocking == SANE_FALSE)
1725141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
1726141cc406Sopenharmony_ci
1727141cc406Sopenharmony_ci	DBG(2, "<< sane_set_io_mode\n");
1728141cc406Sopenharmony_ci	return SANE_STATUS_UNSUPPORTED;
1729141cc406Sopenharmony_ci}
1730141cc406Sopenharmony_ci
1731141cc406Sopenharmony_ci	SANE_Status
1732141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle h, SANE_Int *fdp)
1733141cc406Sopenharmony_ci{
1734141cc406Sopenharmony_ci	DBG(2, ">> sane_get_select_fd (%p, %p) (not supported)\n", h,
1735141cc406Sopenharmony_ci			(const void *)fdp);
1736141cc406Sopenharmony_ci	DBG(2, "<< sane_get_select_fd\n");
1737141cc406Sopenharmony_ci	return SANE_STATUS_UNSUPPORTED;
1738141cc406Sopenharmony_ci}
1739141cc406Sopenharmony_ci
1740141cc406Sopenharmony_ci
1741141cc406Sopenharmony_ci/*************************************************************************
1742141cc406Sopenharmony_ci *
1743141cc406Sopenharmony_ci * init_cal(): Try to create a calibration file
1744141cc406Sopenharmony_ci * has to be changed.
1745141cc406Sopenharmony_ci *
1746141cc406Sopenharmony_ci ************************************************************************/
1747141cc406Sopenharmony_cistatic int init_cal(char *file)
1748141cc406Sopenharmony_ci{
1749141cc406Sopenharmony_ci	char *tmp, *path;
1750141cc406Sopenharmony_ci	int f, i;
1751141cc406Sopenharmony_ci
1752141cc406Sopenharmony_ci	if ((f = open(file, O_CREAT | O_WRONLY, 0600)) < 0)
1753141cc406Sopenharmony_ci	{
1754141cc406Sopenharmony_ci		if (errno == ENOENT)
1755141cc406Sopenharmony_ci		{
1756141cc406Sopenharmony_ci			/* we need to try and make ~/.sane perhaps -
1757141cc406Sopenharmony_ci			 * find the last / in the file path, and try
1758141cc406Sopenharmony_ci			 * to create it */
1759141cc406Sopenharmony_ci			if ((tmp = strrchr(file, '/')) == NULL)
1760141cc406Sopenharmony_ci				return -1;
1761141cc406Sopenharmony_ci			path = strdup(file);
1762141cc406Sopenharmony_ci			*(path + (tmp-file)) = '\0';
1763141cc406Sopenharmony_ci			i = mkdir(path, 0777);
1764141cc406Sopenharmony_ci			free(path);
1765141cc406Sopenharmony_ci			if (i) return -1;
1766141cc406Sopenharmony_ci			/* Path has been created, now try this again.. */
1767141cc406Sopenharmony_ci			if ((f = open(file, O_CREAT | O_WRONLY, 0600)) < 0)
1768141cc406Sopenharmony_ci				return -1;
1769141cc406Sopenharmony_ci		}
1770141cc406Sopenharmony_ci		else
1771141cc406Sopenharmony_ci		{
1772141cc406Sopenharmony_ci			/* Error is something like access denied - too
1773141cc406Sopenharmony_ci			 * hard to fix, so i give up... */
1774141cc406Sopenharmony_ci			return -1;
1775141cc406Sopenharmony_ci		}
1776141cc406Sopenharmony_ci	}
1777141cc406Sopenharmony_ci	/* should probably set defaults here.. */
1778141cc406Sopenharmony_ci	close(f);
1779141cc406Sopenharmony_ci	return 0;
1780141cc406Sopenharmony_ci}
1781141cc406Sopenharmony_ci
1782141cc406Sopenharmony_ci/*************************************************************************
1783141cc406Sopenharmony_ci *
1784141cc406Sopenharmony_ci * fix_weights_file(): Ensures that the weights_file setting for a given
1785141cc406Sopenharmony_ci * scanner is valid
1786141cc406Sopenharmony_ci *
1787141cc406Sopenharmony_ci ************************************************************************/
1788141cc406Sopenharmony_cistatic SANE_Status fix_weights_file(CANONP_Scanner *cs)
1789141cc406Sopenharmony_ci{
1790141cc406Sopenharmony_ci	static const char default_weights_file_prefix[] =
1791141cc406Sopenharmony_ci			"~/.sane/canon_pp-calibration-";
1792141cc406Sopenharmony_ci	char *tmp, *myhome;
1793141cc406Sopenharmony_ci	int i;
1794141cc406Sopenharmony_ci	struct stat *f_stat;
1795141cc406Sopenharmony_ci
1796141cc406Sopenharmony_ci
1797141cc406Sopenharmony_ci	if (cs == NULL)
1798141cc406Sopenharmony_ci	{
1799141cc406Sopenharmony_ci		DBG(0, "fix_weights_file: FATAL: NULL passed by my code, "
1800141cc406Sopenharmony_ci				"please report this!\n");
1801141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
1802141cc406Sopenharmony_ci	}
1803141cc406Sopenharmony_ci
1804141cc406Sopenharmony_ci	/* Assume this is false and then correct it */
1805141cc406Sopenharmony_ci	cs->cal_readonly = SANE_FALSE;
1806141cc406Sopenharmony_ci
1807141cc406Sopenharmony_ci	if (cs->weights_file == NULL)
1808141cc406Sopenharmony_ci	{
1809141cc406Sopenharmony_ci		/* Form is ~/.sane/canon_pp-calibration-parport0 or -0x378 */
1810141cc406Sopenharmony_ci		i = strlen(default_weights_file_prefix) +
1811141cc406Sopenharmony_ci				strlen(cs->params.port->name);
1812141cc406Sopenharmony_ci		if ((cs->weights_file = malloc(i + 1)) == NULL)
1813141cc406Sopenharmony_ci			return SANE_STATUS_NO_MEM;
1814141cc406Sopenharmony_ci		sprintf(cs->weights_file, "%s%s", default_weights_file_prefix,
1815141cc406Sopenharmony_ci				cs->params.port->name);
1816141cc406Sopenharmony_ci	}
1817141cc406Sopenharmony_ci
1818141cc406Sopenharmony_ci	/* Get the user's home dir if they used ~ */
1819141cc406Sopenharmony_ci	if (cs->weights_file[0] == '~')
1820141cc406Sopenharmony_ci	{
1821141cc406Sopenharmony_ci		if ((myhome = getenv("HOME")) == NULL)
1822141cc406Sopenharmony_ci		{
1823141cc406Sopenharmony_ci			DBG(0,"fix_weights_file: FATAL: ~ used, but $HOME not"
1824141cc406Sopenharmony_ci					" set!\n");
1825141cc406Sopenharmony_ci			return SANE_STATUS_INVAL;
1826141cc406Sopenharmony_ci		}
1827141cc406Sopenharmony_ci		i = strlen(myhome) + strlen(&cs->weights_file[1]);
1828141cc406Sopenharmony_ci		if ((tmp = malloc(i + 1)) == NULL)
1829141cc406Sopenharmony_ci			return SANE_STATUS_NO_MEM;
1830141cc406Sopenharmony_ci		sprintf(tmp, "%s%s", myhome, &cs->weights_file[1]);
1831141cc406Sopenharmony_ci
1832141cc406Sopenharmony_ci		free(cs->weights_file);
1833141cc406Sopenharmony_ci		cs->weights_file = tmp;
1834141cc406Sopenharmony_ci		tmp = NULL;
1835141cc406Sopenharmony_ci	}
1836141cc406Sopenharmony_ci
1837141cc406Sopenharmony_ci	if ((f_stat = malloc(sizeof(*f_stat))) == NULL)
1838141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
1839141cc406Sopenharmony_ci
1840141cc406Sopenharmony_ci	if(stat(cs->weights_file, f_stat))
1841141cc406Sopenharmony_ci	{
1842141cc406Sopenharmony_ci		/* this non-intuitive if basically is if we got some error that
1843141cc406Sopenharmony_ci		 * wasn't no-such-file, or we can't create the file.. */
1844141cc406Sopenharmony_ci		if ((errno != ENOENT) || init_cal(cs->weights_file))
1845141cc406Sopenharmony_ci		{
1846141cc406Sopenharmony_ci			/* Some nasty error returned. Give up. */
1847141cc406Sopenharmony_ci			DBG(2,"fix_weights_file: error stating cal file"
1848141cc406Sopenharmony_ci					" (%s)\n", strerror(errno));
1849141cc406Sopenharmony_ci			DBG(2,"fix_weights_file: Changes to cal data won't"
1850141cc406Sopenharmony_ci					" be saved!\n");
1851141cc406Sopenharmony_ci			free(cs->weights_file);
1852141cc406Sopenharmony_ci			cs->weights_file = NULL;
1853141cc406Sopenharmony_ci		}
1854141cc406Sopenharmony_ci	}
1855141cc406Sopenharmony_ci	else
1856141cc406Sopenharmony_ci	{
1857141cc406Sopenharmony_ci
1858141cc406Sopenharmony_ci		/* No error returned.. Check read/writability */
1859141cc406Sopenharmony_ci		i = open(cs->weights_file, O_RDWR | O_APPEND);
1860141cc406Sopenharmony_ci		if (i <= 0)
1861141cc406Sopenharmony_ci		{
1862141cc406Sopenharmony_ci			DBG(10,"fix_weighs_file: Note: Changes to cal data "
1863141cc406Sopenharmony_ci					"won't be saved!\n");
1864141cc406Sopenharmony_ci			i = open(cs->weights_file, O_RDONLY);
1865141cc406Sopenharmony_ci			if (i <= 0)
1866141cc406Sopenharmony_ci			{
1867141cc406Sopenharmony_ci				/*
1868141cc406Sopenharmony_ci				 * Open failed (do i care why?)
1869141cc406Sopenharmony_ci				 */
1870141cc406Sopenharmony_ci				DBG(2,"fix_weights_file: error opening cal "
1871141cc406Sopenharmony_ci						"(%s)\n", strerror(errno));
1872141cc406Sopenharmony_ci				free(cs->weights_file);
1873141cc406Sopenharmony_ci				cs->weights_file = NULL;
1874141cc406Sopenharmony_ci			}
1875141cc406Sopenharmony_ci			else
1876141cc406Sopenharmony_ci			{
1877141cc406Sopenharmony_ci				DBG(2,"fix_weights_file: file is read-only, "
1878141cc406Sopenharmony_ci						"changes won't be saved\n");
1879141cc406Sopenharmony_ci				cs->cal_readonly = SANE_TRUE;
1880141cc406Sopenharmony_ci				close(i);
1881141cc406Sopenharmony_ci			}
1882141cc406Sopenharmony_ci		}
1883141cc406Sopenharmony_ci		else
1884141cc406Sopenharmony_ci		{
1885141cc406Sopenharmony_ci			/* good! */
1886141cc406Sopenharmony_ci			DBG(10,"fix_weights_file: Calibration file is good "
1887141cc406Sopenharmony_ci					"for opening!\n");
1888141cc406Sopenharmony_ci			close(i);
1889141cc406Sopenharmony_ci		}
1890141cc406Sopenharmony_ci	}
1891141cc406Sopenharmony_ci
1892141cc406Sopenharmony_ci	/* cleanup */
1893141cc406Sopenharmony_ci	free(f_stat);
1894141cc406Sopenharmony_ci
1895141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1896141cc406Sopenharmony_ci}
1897141cc406Sopenharmony_ci
1898141cc406Sopenharmony_ci/* detect_mode
1899141cc406Sopenharmony_ci * PRE:
1900141cc406Sopenharmony_ci *	cs->params.port is not open
1901141cc406Sopenharmony_ci * POST:
1902141cc406Sopenharmony_ci * 	cs->params.port is left opened iff SANE_STATUS_GOOD returned.
1903141cc406Sopenharmony_ci */
1904141cc406Sopenharmony_ci
1905141cc406Sopenharmony_ciSANE_Status detect_mode(CANONP_Scanner *cs)
1906141cc406Sopenharmony_ci{
1907141cc406Sopenharmony_ci
1908141cc406Sopenharmony_ci	int capabilities, tmp;
1909141cc406Sopenharmony_ci
1910141cc406Sopenharmony_ci	/* Open then claim parallel port using libieee1284 */
1911141cc406Sopenharmony_ci	DBG(10,"detect_mode: Opening port %s\n", (cs->params.port->name));
1912141cc406Sopenharmony_ci
1913141cc406Sopenharmony_ci	tmp = ieee1284_open(cs->params.port, 0, &capabilities);
1914141cc406Sopenharmony_ci
1915141cc406Sopenharmony_ci	if (tmp != E1284_OK)
1916141cc406Sopenharmony_ci	{
1917141cc406Sopenharmony_ci		switch (tmp)
1918141cc406Sopenharmony_ci		{
1919141cc406Sopenharmony_ci			case E1284_INVALIDPORT:
1920141cc406Sopenharmony_ci				DBG(1, "detect_mode: Invalid port.\n");
1921141cc406Sopenharmony_ci				break;
1922141cc406Sopenharmony_ci			case E1284_SYS:
1923141cc406Sopenharmony_ci				DBG(1, "detect_mode: System error: %s\n",
1924141cc406Sopenharmony_ci						strerror(errno));
1925141cc406Sopenharmony_ci				break;
1926141cc406Sopenharmony_ci			case E1284_INIT:
1927141cc406Sopenharmony_ci				DBG(1, "detect_mode: Initialisation error.\n");
1928141cc406Sopenharmony_ci				break;
1929141cc406Sopenharmony_ci			default:
1930141cc406Sopenharmony_ci				DBG(1, "detect_mode: Unknown error.\n");
1931141cc406Sopenharmony_ci				break;
1932141cc406Sopenharmony_ci		}
1933141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1934141cc406Sopenharmony_ci	}
1935141cc406Sopenharmony_ci
1936141cc406Sopenharmony_ci	DBG(10,"detect_mode: Claiming port.\n");
1937141cc406Sopenharmony_ci
1938141cc406Sopenharmony_ci	if (ieee1284_claim(cs->params.port) != E1284_OK)
1939141cc406Sopenharmony_ci	{
1940141cc406Sopenharmony_ci		DBG(1,"detect_mode: Unable to claim port\n");
1941141cc406Sopenharmony_ci		ieee1284_close(cs->params.port);
1942141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1943141cc406Sopenharmony_ci	}
1944141cc406Sopenharmony_ci
1945141cc406Sopenharmony_ci
1946141cc406Sopenharmony_ci	/* Check that compatibility-mode (required) is supported */
1947141cc406Sopenharmony_ci	if (!(capabilities & CAP1284_COMPAT))
1948141cc406Sopenharmony_ci	{
1949141cc406Sopenharmony_ci		DBG(0,"detect_mode: Compatibility mode (required) not "
1950141cc406Sopenharmony_ci				"supported.\n");
1951141cc406Sopenharmony_ci		ieee1284_release(cs->params.port);
1952141cc406Sopenharmony_ci		ieee1284_close(cs->params.port);
1953141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1954141cc406Sopenharmony_ci	}
1955141cc406Sopenharmony_ci
1956141cc406Sopenharmony_ci	/* Check capabilities which will enchance speed */
1957141cc406Sopenharmony_ci	if (capabilities & CAP1284_ECP)
1958141cc406Sopenharmony_ci		DBG(2, "detect_mode: Port supports ECP-H.\n");
1959141cc406Sopenharmony_ci	else if (capabilities & CAP1284_ECPSWE)
1960141cc406Sopenharmony_ci		DBG(2, "detect_mode: Port supports ECP-S.\n");
1961141cc406Sopenharmony_ci	if (capabilities & CAP1284_IRQ)
1962141cc406Sopenharmony_ci		DBG(2, "detect_mode: Port supports interrupts.\n");
1963141cc406Sopenharmony_ci	if (capabilities & CAP1284_DMA)
1964141cc406Sopenharmony_ci		DBG(2, "detect_mode: Port supports DMA.\n");
1965141cc406Sopenharmony_ci
1966141cc406Sopenharmony_ci	/* Check whether ECP mode is possible */
1967141cc406Sopenharmony_ci	if (capabilities & CAP1284_ECP)
1968141cc406Sopenharmony_ci	{
1969141cc406Sopenharmony_ci		cs->ieee1284_mode = M1284_ECP;
1970141cc406Sopenharmony_ci		DBG(10, "detect_mode: Using ECP-H Mode\n");
1971141cc406Sopenharmony_ci	}
1972141cc406Sopenharmony_ci	else if (capabilities & CAP1284_ECPSWE)
1973141cc406Sopenharmony_ci	{
1974141cc406Sopenharmony_ci		cs->ieee1284_mode = M1284_ECPSWE;
1975141cc406Sopenharmony_ci		DBG(10, "detect_mode: Using ECP-S Mode\n");
1976141cc406Sopenharmony_ci	}
1977141cc406Sopenharmony_ci	else if (capabilities & CAP1284_NIBBLE)
1978141cc406Sopenharmony_ci	{
1979141cc406Sopenharmony_ci		cs->ieee1284_mode = M1284_NIBBLE;
1980141cc406Sopenharmony_ci		DBG(10, "detect_mode: Using nibble mode\n");
1981141cc406Sopenharmony_ci	}
1982141cc406Sopenharmony_ci	else
1983141cc406Sopenharmony_ci	{
1984141cc406Sopenharmony_ci		DBG(0, "detect_mode: No supported parport modes available!\n");
1985141cc406Sopenharmony_ci		ieee1284_release(cs->params.port);
1986141cc406Sopenharmony_ci		ieee1284_close(cs->params.port);
1987141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1988141cc406Sopenharmony_ci	}
1989141cc406Sopenharmony_ci
1990141cc406Sopenharmony_ci	/* Check to make sure ECP mode really is supported */
1991141cc406Sopenharmony_ci	/* Have disabled the hardware ECP check because it's always supported
1992141cc406Sopenharmony_ci	 * by libieee1284 now, and it's too prone to hitting a ppdev bug
1993141cc406Sopenharmony_ci	 */
1994141cc406Sopenharmony_ci
1995141cc406Sopenharmony_ci	/* Disabled check entirely.. check now in initialise when we
1996141cc406Sopenharmony_ci	 * actually do a read */
1997141cc406Sopenharmony_ci#if 0
1998141cc406Sopenharmony_ci	if ((cs->ieee1284_mode == M1284_ECP) ||
1999141cc406Sopenharmony_ci			(cs->ieee1284_mode == M1284_ECPSWE))
2000141cc406Sopenharmony_ci	{
2001141cc406Sopenharmony_ci		DBG(1, "detect_mode: attempting a 0 byte read, if we hang "
2002141cc406Sopenharmony_ci				"here, it's a ppdev bug!\n");
2003141cc406Sopenharmony_ci		/*
2004141cc406Sopenharmony_ci		 * 29/06/02
2005141cc406Sopenharmony_ci		 * NOTE:
2006141cc406Sopenharmony_ci		 * This causes an infinite loop in ppdev on 2.4.18.
2007141cc406Sopenharmony_ci		 * Not checking on hardware ECP mode should work-around
2008141cc406Sopenharmony_ci		 * effectively.
2009141cc406Sopenharmony_ci		 *
2010141cc406Sopenharmony_ci		 * I have sent email to twaugh about it, should be fixed in
2011141cc406Sopenharmony_ci		 * 2.4.19 and above.
2012141cc406Sopenharmony_ci		 */
2013141cc406Sopenharmony_ci		if (ieee1284_ecp_read_data(cs->params.port, 0, NULL, 0) ==
2014141cc406Sopenharmony_ci				E1284_NOTIMPL)
2015141cc406Sopenharmony_ci		{
2016141cc406Sopenharmony_ci			DBG(10, "detect_mode: Your version of libieee1284 "
2017141cc406Sopenharmony_ci					"doesn't support ECP mode - defaulting"
2018141cc406Sopenharmony_ci					" to nibble mode instead.\n");
2019141cc406Sopenharmony_ci			cs->ieee1284_mode = M1284_NIBBLE;
2020141cc406Sopenharmony_ci		}
2021141cc406Sopenharmony_ci	}
2022141cc406Sopenharmony_ci#endif
2023141cc406Sopenharmony_ci
2024141cc406Sopenharmony_ci	if (force_nibble == SANE_TRUE) {
2025141cc406Sopenharmony_ci		DBG(10, "detect_mode: Nibble mode force in effect.\n");
2026141cc406Sopenharmony_ci		cs->ieee1284_mode = M1284_NIBBLE;
2027141cc406Sopenharmony_ci	}
2028141cc406Sopenharmony_ci
2029141cc406Sopenharmony_ci	ieee1284_release(cs->params.port);
2030141cc406Sopenharmony_ci
2031141cc406Sopenharmony_ci	sanei_canon_pp_set_ieee1284_mode(cs->ieee1284_mode);
2032141cc406Sopenharmony_ci
2033141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
2034141cc406Sopenharmony_ci}
2035