1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2009-12 Stéphane Voltz <stef.dev@free.fr>
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/*   --------------------------------------------------------------------------
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci*/
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
23141cc406Sopenharmony_ci/*! \mainpage Primax PagePartner Parallel Port scanner Index Page
24141cc406Sopenharmony_ci *
25141cc406Sopenharmony_ci * \section intro_sec Introduction
26141cc406Sopenharmony_ci *
27141cc406Sopenharmony_ci * This backend provides support for the Prima PagePartner sheet fed parallel
28141cc406Sopenharmony_ci * port scanner.
29141cc406Sopenharmony_ci *
30141cc406Sopenharmony_ci * \section sane_api SANE API
31141cc406Sopenharmony_ci *
32141cc406Sopenharmony_ci * \subsection sane_flow sane flow
33141cc406Sopenharmony_ci   SANE FLOW
34141cc406Sopenharmony_ci   - sane_init() : initialize backend, attach scanners.
35141cc406Sopenharmony_ci   	- sane_get_devices() : query list of scanner devices, backend must
36141cc406Sopenharmony_ci                           	probe for new devices.
37141cc406Sopenharmony_ci   	- sane_open() : open a particular scanner device, adding a handle
38141cc406Sopenharmony_ci   		     	to the opened device
39141cc406Sopenharmony_ci		- sane_set_io_mode() : set blocking mode
40141cc406Sopenharmony_ci		- sane_get_select_fd() : get scanner fd
41141cc406Sopenharmony_ci		- sane_get_option_descriptor() : get option information
42141cc406Sopenharmony_ci		- sane_control_option() : change option values
43141cc406Sopenharmony_ci		- sane_start() : start image acquisition
44141cc406Sopenharmony_ci			- sane_get_parameters() : returns actual scan parameters for the ongoing scan
45141cc406Sopenharmony_ci			- sane_read() : read image data
46141cc406Sopenharmony_ci		- sane_cancel() : cancel operation, end scan
47141cc406Sopenharmony_ci   	- sane_close() : close opened scanner device, freeing scanner handle
48141cc406Sopenharmony_ci   - sane_exit() : terminate use of backend, freeing all resources for attached
49141cc406Sopenharmony_ci   		   devices when last frontend quits
50141cc406Sopenharmony_ci */
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ci/**
53141cc406Sopenharmony_ci * the build number allow to know which version of the backend is running.
54141cc406Sopenharmony_ci */
55141cc406Sopenharmony_ci#define BUILD 2301
56141cc406Sopenharmony_ci
57141cc406Sopenharmony_ci#include "p5.h"
58141cc406Sopenharmony_ci
59141cc406Sopenharmony_ci/**
60141cc406Sopenharmony_ci * Import directly the low level part needed to
61141cc406Sopenharmony_ci * operate scanner. The alternative is to prefix all public functions
62141cc406Sopenharmony_ci * with sanei_p5_ ,and have all the functions prototyped in
63141cc406Sopenharmony_ci * p5_device.h .
64141cc406Sopenharmony_ci */
65141cc406Sopenharmony_ci#include "p5_device.c"
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_ci/**
68141cc406Sopenharmony_ci * number of time the backend has been loaded by sane_init.
69141cc406Sopenharmony_ci */
70141cc406Sopenharmony_cistatic int init_count = 0;
71141cc406Sopenharmony_ci
72141cc406Sopenharmony_ci/**
73141cc406Sopenharmony_ci * NULL terminated list of opened frontend sessions. Sessions are
74141cc406Sopenharmony_ci * inserted here on sane_open() and removed on sane_close().
75141cc406Sopenharmony_ci */
76141cc406Sopenharmony_cistatic P5_Session *sessions = NULL;
77141cc406Sopenharmony_ci
78141cc406Sopenharmony_ci/**
79141cc406Sopenharmony_ci * NULL terminated list of detected physical devices.
80141cc406Sopenharmony_ci * The same device may be opened several time by different sessions.
81141cc406Sopenharmony_ci * Entry are inserted here by the attach() function.
82141cc406Sopenharmony_ci * */
83141cc406Sopenharmony_cistatic P5_Device *devices = NULL;
84141cc406Sopenharmony_ci
85141cc406Sopenharmony_ci/**
86141cc406Sopenharmony_ci * NULL terminated list of devices needed by sane_get_devices(), since
87141cc406Sopenharmony_ci * the result returned must stay consistent until next call.
88141cc406Sopenharmony_ci */
89141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
90141cc406Sopenharmony_ci
91141cc406Sopenharmony_ci/**
92141cc406Sopenharmony_ci * list of possible color modes
93141cc406Sopenharmony_ci */
94141cc406Sopenharmony_cistatic SANE_String_Const mode_list[] = {
95141cc406Sopenharmony_ci  SANE_I18N (COLOR_MODE),
96141cc406Sopenharmony_ci  SANE_I18N (GRAY_MODE),
97141cc406Sopenharmony_ci  /* SANE_I18N (LINEART_MODE), not supported yet */
98141cc406Sopenharmony_ci  0
99141cc406Sopenharmony_ci};
100141cc406Sopenharmony_ci
101141cc406Sopenharmony_cistatic SANE_Range x_range = {
102141cc406Sopenharmony_ci  SANE_FIX (0.0),		/* minimum */
103141cc406Sopenharmony_ci  SANE_FIX (216.0),		/* maximum */
104141cc406Sopenharmony_ci  SANE_FIX (0.0)		/* quantization */
105141cc406Sopenharmony_ci};
106141cc406Sopenharmony_ci
107141cc406Sopenharmony_cistatic SANE_Range y_range = {
108141cc406Sopenharmony_ci  SANE_FIX (0.0),		/* minimum */
109141cc406Sopenharmony_ci  SANE_FIX (299.0),		/* maximum */
110141cc406Sopenharmony_ci  SANE_FIX (0.0)		/* no quantization */
111141cc406Sopenharmony_ci};
112141cc406Sopenharmony_ci
113141cc406Sopenharmony_ci/**
114141cc406Sopenharmony_ci * finds the maximum string length in a string array.
115141cc406Sopenharmony_ci */
116141cc406Sopenharmony_cistatic size_t
117141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
118141cc406Sopenharmony_ci{
119141cc406Sopenharmony_ci  size_t size, max_size = 0;
120141cc406Sopenharmony_ci  SANE_Int i;
121141cc406Sopenharmony_ci
122141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
123141cc406Sopenharmony_ci    {
124141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
125141cc406Sopenharmony_ci      if (size > max_size)
126141cc406Sopenharmony_ci	max_size = size;
127141cc406Sopenharmony_ci    }
128141cc406Sopenharmony_ci  return max_size;
129141cc406Sopenharmony_ci}
130141cc406Sopenharmony_ci
131141cc406Sopenharmony_ci/**> placeholders for decoded configuration values */
132141cc406Sopenharmony_cistatic P5_Config p5cfg;
133141cc406Sopenharmony_ci
134141cc406Sopenharmony_ci
135141cc406Sopenharmony_ci/* ------------------------------------------------------------------------- */
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_ci/*
138141cc406Sopenharmony_ci * SANE Interface
139141cc406Sopenharmony_ci */
140141cc406Sopenharmony_ci
141141cc406Sopenharmony_ci
142141cc406Sopenharmony_ci/**
143141cc406Sopenharmony_ci * Called by SANE initially.
144141cc406Sopenharmony_ci *
145141cc406Sopenharmony_ci * From the SANE spec:
146141cc406Sopenharmony_ci * This function must be called before any other SANE function can be
147141cc406Sopenharmony_ci * called. The behavior of a SANE backend is undefined if this
148141cc406Sopenharmony_ci * function is not called first. The version code of the backend is
149141cc406Sopenharmony_ci * returned in the value pointed to by version_code. If that pointer
150141cc406Sopenharmony_ci * is NULL, no version code is returned. Argument authorize is either
151141cc406Sopenharmony_ci * a pointer to a function that is invoked when the backend requires
152141cc406Sopenharmony_ci * authentication for a specific resource or NULL if the frontend does
153141cc406Sopenharmony_ci * not support authentication.
154141cc406Sopenharmony_ci */
155141cc406Sopenharmony_ciSANE_Status
156141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
157141cc406Sopenharmony_ci{
158141cc406Sopenharmony_ci  SANE_Status status;
159141cc406Sopenharmony_ci
160141cc406Sopenharmony_ci  (void) authorize;		/* get rid of compiler warning */
161141cc406Sopenharmony_ci
162141cc406Sopenharmony_ci  init_count++;
163141cc406Sopenharmony_ci
164141cc406Sopenharmony_ci  /* init backend debug */
165141cc406Sopenharmony_ci  DBG_INIT ();
166141cc406Sopenharmony_ci  DBG (DBG_info, "SANE P5 backend version %d.%d-%d\n",
167141cc406Sopenharmony_ci       SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
168141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_init: start\n");
169141cc406Sopenharmony_ci  DBG (DBG_trace, "sane_init: init_count=%d\n", init_count);
170141cc406Sopenharmony_ci
171141cc406Sopenharmony_ci  if (version_code)
172141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
173141cc406Sopenharmony_ci
174141cc406Sopenharmony_ci  /* cold-plugging case : probe for already plugged devices */
175141cc406Sopenharmony_ci  status = probe_p5_devices ();
176141cc406Sopenharmony_ci
177141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_init: exit\n");
178141cc406Sopenharmony_ci  return status;
179141cc406Sopenharmony_ci}
180141cc406Sopenharmony_ci
181141cc406Sopenharmony_ci
182141cc406Sopenharmony_ci/**
183141cc406Sopenharmony_ci * Called by SANE to find out about supported devices.
184141cc406Sopenharmony_ci *
185141cc406Sopenharmony_ci * From the SANE spec:
186141cc406Sopenharmony_ci * This function can be used to query the list of devices that are
187141cc406Sopenharmony_ci * available. If the function executes successfully, it stores a
188141cc406Sopenharmony_ci * pointer to a NULL terminated array of pointers to SANE_Device
189141cc406Sopenharmony_ci * structures in *device_list. The returned list is guaranteed to
190141cc406Sopenharmony_ci * remain unchanged and valid until (a) another call to this function
191141cc406Sopenharmony_ci * is performed or (b) a call to sane_exit() is performed. This
192141cc406Sopenharmony_ci * function can be called repeatedly to detect when new devices become
193141cc406Sopenharmony_ci * available. If argument local_only is true, only local devices are
194141cc406Sopenharmony_ci * returned (devices directly attached to the machine that SANE is
195141cc406Sopenharmony_ci * running on). If it is false, the device list includes all remote
196141cc406Sopenharmony_ci * devices that are accessible to the SANE library.
197141cc406Sopenharmony_ci *
198141cc406Sopenharmony_ci * SANE does not require that this function is called before a
199141cc406Sopenharmony_ci * sane_open() call is performed. A device name may be specified
200141cc406Sopenharmony_ci * explicitly by a user which would make it unnecessary and
201141cc406Sopenharmony_ci * undesirable to call this function first.
202141cc406Sopenharmony_ci * @param device_list pointer where to store the device list
203141cc406Sopenharmony_ci * @param local_only SANE_TRUE if only local devices are required.
204141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD when successful
205141cc406Sopenharmony_ci */
206141cc406Sopenharmony_ciSANE_Status
207141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
208141cc406Sopenharmony_ci{
209141cc406Sopenharmony_ci  int dev_num, devnr;
210141cc406Sopenharmony_ci  struct P5_Device *device;
211141cc406Sopenharmony_ci  SANE_Device *sane_device;
212141cc406Sopenharmony_ci  int i;
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_devices: start: local_only = %s\n",
215141cc406Sopenharmony_ci       local_only == SANE_TRUE ? "true" : "false");
216141cc406Sopenharmony_ci
217141cc406Sopenharmony_ci  /* free existing devlist first */
218141cc406Sopenharmony_ci  if (devlist)
219141cc406Sopenharmony_ci    {
220141cc406Sopenharmony_ci      for (i = 0; devlist[i] != NULL; i++)
221141cc406Sopenharmony_ci	free ((void *)devlist[i]);
222141cc406Sopenharmony_ci      free (devlist);
223141cc406Sopenharmony_ci      devlist = NULL;
224141cc406Sopenharmony_ci    }
225141cc406Sopenharmony_ci
226141cc406Sopenharmony_ci  /**
227141cc406Sopenharmony_ci   * Since sane_get_devices() may be called repeatedly to detect new devices,
228141cc406Sopenharmony_ci   * the device detection must be run at each call. We are handling
229141cc406Sopenharmony_ci   * hot-plugging : we probe for devices plugged since sane_init() was called.
230141cc406Sopenharmony_ci   */
231141cc406Sopenharmony_ci  probe_p5_devices ();
232141cc406Sopenharmony_ci
233141cc406Sopenharmony_ci  /* if no devices detected, just return an empty list */
234141cc406Sopenharmony_ci  if (devices == NULL)
235141cc406Sopenharmony_ci    {
236141cc406Sopenharmony_ci      devlist = malloc (sizeof (devlist[0]));
237141cc406Sopenharmony_ci      if (!devlist)
238141cc406Sopenharmony_ci	return SANE_STATUS_NO_MEM;
239141cc406Sopenharmony_ci      devlist[0] = NULL;
240141cc406Sopenharmony_ci      *device_list = devlist;
241141cc406Sopenharmony_ci      DBG (DBG_proc, "sane_get_devices: exit with no device\n");
242141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
243141cc406Sopenharmony_ci    }
244141cc406Sopenharmony_ci
245141cc406Sopenharmony_ci  /* count physical devices */
246141cc406Sopenharmony_ci  devnr = 1;
247141cc406Sopenharmony_ci  device = devices;
248141cc406Sopenharmony_ci  while (device->next)
249141cc406Sopenharmony_ci    {
250141cc406Sopenharmony_ci      devnr++;
251141cc406Sopenharmony_ci      device = device->next;
252141cc406Sopenharmony_ci    }
253141cc406Sopenharmony_ci
254141cc406Sopenharmony_ci  /* allocate room for the list, plus 1 for the NULL terminator */
255141cc406Sopenharmony_ci  devlist = malloc ((devnr + 1) * sizeof (devlist[0]));
256141cc406Sopenharmony_ci  if (!devlist)
257141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
258141cc406Sopenharmony_ci
259141cc406Sopenharmony_ci  *device_list = devlist;
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_ci  dev_num = 0;
262141cc406Sopenharmony_ci  device = devices;
263141cc406Sopenharmony_ci
264141cc406Sopenharmony_ci  /* we build a list of SANE_Device from the list of attached devices */
265141cc406Sopenharmony_ci  for (i = 0; i < devnr; i++)
266141cc406Sopenharmony_ci    {
267141cc406Sopenharmony_ci      /* add device according to local only flag */
268141cc406Sopenharmony_ci      if ((local_only == SANE_TRUE && device->local == SANE_TRUE)
269141cc406Sopenharmony_ci	  || local_only == SANE_FALSE)
270141cc406Sopenharmony_ci	{
271141cc406Sopenharmony_ci	  /* allocate memory to add the device */
272141cc406Sopenharmony_ci	  sane_device = malloc (sizeof (*sane_device));
273141cc406Sopenharmony_ci	  if (!sane_device)
274141cc406Sopenharmony_ci	    {
275141cc406Sopenharmony_ci	      return SANE_STATUS_NO_MEM;
276141cc406Sopenharmony_ci	    }
277141cc406Sopenharmony_ci
278141cc406Sopenharmony_ci	  /* copy data */
279141cc406Sopenharmony_ci	  sane_device->name = device->name;
280141cc406Sopenharmony_ci	  sane_device->vendor = device->model->vendor;
281141cc406Sopenharmony_ci	  sane_device->model = device->model->product;
282141cc406Sopenharmony_ci	  sane_device->type = device->model->type;
283141cc406Sopenharmony_ci	  devlist[dev_num] = sane_device;
284141cc406Sopenharmony_ci
285141cc406Sopenharmony_ci	  /* increment device counter */
286141cc406Sopenharmony_ci	  dev_num++;
287141cc406Sopenharmony_ci	}
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_ci      /* go to next detected device */
290141cc406Sopenharmony_ci      device = device->next;
291141cc406Sopenharmony_ci    }
292141cc406Sopenharmony_ci  devlist[dev_num] = 0;
293141cc406Sopenharmony_ci
294141cc406Sopenharmony_ci  *device_list = devlist;
295141cc406Sopenharmony_ci
296141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_devices: exit\n");
297141cc406Sopenharmony_ci
298141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
299141cc406Sopenharmony_ci}
300141cc406Sopenharmony_ci
301141cc406Sopenharmony_ci
302141cc406Sopenharmony_ci/**
303141cc406Sopenharmony_ci * Called to establish connection with the session. This function will
304141cc406Sopenharmony_ci * also establish meaningful defaults and initialize the options.
305141cc406Sopenharmony_ci *
306141cc406Sopenharmony_ci * From the SANE spec:
307141cc406Sopenharmony_ci * This function is used to establish a connection to a particular
308141cc406Sopenharmony_ci * device. The name of the device to be opened is passed in argument
309141cc406Sopenharmony_ci * name. If the call completes successfully, a handle for the device
310141cc406Sopenharmony_ci * is returned in *h. As a special case, specifying a zero-length
311141cc406Sopenharmony_ci * string as the device requests opening the first available device
312141cc406Sopenharmony_ci * (if there is such a device). Another special case is to only give
313141cc406Sopenharmony_ci * the name of the backend as the device name, in this case the first
314141cc406Sopenharmony_ci * available device will also be used.
315141cc406Sopenharmony_ci * @param name name of the device to open
316141cc406Sopenharmony_ci * @param handle opaque pointer where to store the pointer of
317141cc406Sopenharmony_ci *        the opened P5_Session
318141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD on success
319141cc406Sopenharmony_ci */
320141cc406Sopenharmony_ciSANE_Status
321141cc406Sopenharmony_cisane_open (SANE_String_Const name, SANE_Handle * handle)
322141cc406Sopenharmony_ci{
323141cc406Sopenharmony_ci  struct P5_Session *session = NULL;
324141cc406Sopenharmony_ci  struct P5_Device *device = NULL;
325141cc406Sopenharmony_ci
326141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_open: start (devicename=%s)\n", name);
327141cc406Sopenharmony_ci
328141cc406Sopenharmony_ci  /* check there is at least a device */
329141cc406Sopenharmony_ci  if (devices == NULL)
330141cc406Sopenharmony_ci    {
331141cc406Sopenharmony_ci      DBG (DBG_proc, "sane_open: exit, no device to open!\n");
332141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
333141cc406Sopenharmony_ci    }
334141cc406Sopenharmony_ci
335141cc406Sopenharmony_ci  if (name[0] == 0 || strncmp (name, "p5", strlen ("p5")) == 0)
336141cc406Sopenharmony_ci    {
337141cc406Sopenharmony_ci      DBG (DBG_info,
338141cc406Sopenharmony_ci	   "sane_open: no specific device requested, using default\n");
339141cc406Sopenharmony_ci      if (devices)
340141cc406Sopenharmony_ci	{
341141cc406Sopenharmony_ci	  device = devices;
342141cc406Sopenharmony_ci	  DBG (DBG_info, "sane_open: device %s used as default device\n",
343141cc406Sopenharmony_ci	       device->name);
344141cc406Sopenharmony_ci	}
345141cc406Sopenharmony_ci    }
346141cc406Sopenharmony_ci  else
347141cc406Sopenharmony_ci    {
348141cc406Sopenharmony_ci      DBG (DBG_info, "sane_open: device %s requested\n", name);
349141cc406Sopenharmony_ci      /* walk the device list until we find a matching name */
350141cc406Sopenharmony_ci      device = devices;
351141cc406Sopenharmony_ci      while (device && strcmp (device->name, name) != 0)
352141cc406Sopenharmony_ci	{
353141cc406Sopenharmony_ci	  DBG (DBG_trace, "sane_open: device %s doesn't match\n",
354141cc406Sopenharmony_ci	       device->name);
355141cc406Sopenharmony_ci	  device = device->next;
356141cc406Sopenharmony_ci	}
357141cc406Sopenharmony_ci    }
358141cc406Sopenharmony_ci
359141cc406Sopenharmony_ci  /* check whether we have found a match or reach the end of the device list */
360141cc406Sopenharmony_ci  if (!device)
361141cc406Sopenharmony_ci    {
362141cc406Sopenharmony_ci      DBG (DBG_info, "sane_open: no device found\n");
363141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
364141cc406Sopenharmony_ci    }
365141cc406Sopenharmony_ci
366141cc406Sopenharmony_ci  /* now we have a device, duplicate it and return it in handle */
367141cc406Sopenharmony_ci  DBG (DBG_info, "sane_open: device %s found\n", name);
368141cc406Sopenharmony_ci
369141cc406Sopenharmony_ci  /* device initialization */
370141cc406Sopenharmony_ci  if (device->initialized == SANE_FALSE)
371141cc406Sopenharmony_ci    {
372141cc406Sopenharmony_ci      /**
373141cc406Sopenharmony_ci       * call to hardware initialization function here.
374141cc406Sopenharmony_ci       */
375141cc406Sopenharmony_ci      device->fd = open_pp (device->name);
376141cc406Sopenharmony_ci      if (device->fd < 0)
377141cc406Sopenharmony_ci	{
378141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_open: failed to open '%s' device!\n",
379141cc406Sopenharmony_ci	       device->name);
380141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
381141cc406Sopenharmony_ci	}
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_ci      /* now try to connect to scanner */
384141cc406Sopenharmony_ci      if (connect (device->fd) != SANE_TRUE)
385141cc406Sopenharmony_ci	{
386141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_open: failed to connect!\n");
387141cc406Sopenharmony_ci	  close_pp (device->fd);
388141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
389141cc406Sopenharmony_ci	}
390141cc406Sopenharmony_ci
391141cc406Sopenharmony_ci      /* load calibration data */
392141cc406Sopenharmony_ci      restore_calibration (device);
393141cc406Sopenharmony_ci
394141cc406Sopenharmony_ci      /* device link is OK now */
395141cc406Sopenharmony_ci      device->initialized = SANE_TRUE;
396141cc406Sopenharmony_ci    }
397141cc406Sopenharmony_ci  device->buffer = NULL;
398141cc406Sopenharmony_ci  device->gain = NULL;
399141cc406Sopenharmony_ci  device->offset = NULL;
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci  /* prepare handle to return */
402141cc406Sopenharmony_ci  session = (P5_Session *) malloc (sizeof (P5_Session));
403141cc406Sopenharmony_ci  if (session == NULL)
404141cc406Sopenharmony_ci    {
405141cc406Sopenharmony_ci      DBG (DBG_proc, "sane_open: exit OOM\n");
406141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
407141cc406Sopenharmony_ci    }
408141cc406Sopenharmony_ci
409141cc406Sopenharmony_ci  /* initialize session */
410141cc406Sopenharmony_ci  session->dev = device;
411141cc406Sopenharmony_ci  session->scanning = SANE_FALSE;
412141cc406Sopenharmony_ci  session->non_blocking = SANE_FALSE;
413141cc406Sopenharmony_ci
414141cc406Sopenharmony_ci  /* initialize SANE options for this session */
415141cc406Sopenharmony_ci  init_options (session);
416141cc406Sopenharmony_ci
417141cc406Sopenharmony_ci  /* add the handle to the linked list of sessions */
418141cc406Sopenharmony_ci  session->next = sessions;
419141cc406Sopenharmony_ci  sessions = session;
420141cc406Sopenharmony_ci
421141cc406Sopenharmony_ci  /* store result */
422141cc406Sopenharmony_ci  *handle = session;
423141cc406Sopenharmony_ci
424141cc406Sopenharmony_ci  /* exit success */
425141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_open: exit\n");
426141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
427141cc406Sopenharmony_ci}
428141cc406Sopenharmony_ci
429141cc406Sopenharmony_ci
430141cc406Sopenharmony_ci/**
431141cc406Sopenharmony_ci * Set non blocking mode. In this mode, read return immediately when
432141cc406Sopenharmony_ci * no data is available within sane_read(), instead of polling the scanner.
433141cc406Sopenharmony_ci */
434141cc406Sopenharmony_ciSANE_Status
435141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
436141cc406Sopenharmony_ci{
437141cc406Sopenharmony_ci  P5_Session *session = (P5_Session *) handle;
438141cc406Sopenharmony_ci
439141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_set_io_mode: start\n");
440141cc406Sopenharmony_ci  if (session->scanning != SANE_TRUE)
441141cc406Sopenharmony_ci    {
442141cc406Sopenharmony_ci      DBG (DBG_error, "sane_set_io_mode: called out of a scan\n");
443141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
444141cc406Sopenharmony_ci    }
445141cc406Sopenharmony_ci  session->non_blocking = non_blocking;
446141cc406Sopenharmony_ci  DBG (DBG_info, "sane_set_io_mode: I/O mode set to %sblocking.\n",
447141cc406Sopenharmony_ci       non_blocking ? "non " : " ");
448141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_set_io_mode: exit\n");
449141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
450141cc406Sopenharmony_ci}
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci
453141cc406Sopenharmony_ci/**
454141cc406Sopenharmony_ci * An advanced method we don't support but have to define. At SANE API
455141cc406Sopenharmony_ci * level this function is meant to provide a file descriptor on which the
456141cc406Sopenharmony_ci * frontend can do select()/poll() to wait for data.
457141cc406Sopenharmony_ci */
458141cc406Sopenharmony_ciSANE_Status
459141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fdp)
460141cc406Sopenharmony_ci{
461141cc406Sopenharmony_ci  /* make compiler happy ... */
462141cc406Sopenharmony_ci  (void) handle;
463141cc406Sopenharmony_ci  (void) fdp;
464141cc406Sopenharmony_ci
465141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_select_fd: start\n");
466141cc406Sopenharmony_ci  DBG (DBG_warn, "sane_get_select_fd: unsupported ...\n");
467141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_select_fd: exit\n");
468141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
469141cc406Sopenharmony_ci}
470141cc406Sopenharmony_ci
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci/**
473141cc406Sopenharmony_ci * Returns the options we know.
474141cc406Sopenharmony_ci *
475141cc406Sopenharmony_ci * From the SANE spec:
476141cc406Sopenharmony_ci * This function is used to access option descriptors. The function
477141cc406Sopenharmony_ci * returns the option descriptor for option number n of the device
478141cc406Sopenharmony_ci * represented by handle h. Option number 0 is guaranteed to be a
479141cc406Sopenharmony_ci * valid option. Its value is an integer that specifies the number of
480141cc406Sopenharmony_ci * options that are available for device handle h (the count includes
481141cc406Sopenharmony_ci * option 0). If n is not a valid option index, the function returns
482141cc406Sopenharmony_ci * NULL. The returned option descriptor is guaranteed to remain valid
483141cc406Sopenharmony_ci * (and at the returned address) until the device is closed.
484141cc406Sopenharmony_ci */
485141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
486141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
487141cc406Sopenharmony_ci{
488141cc406Sopenharmony_ci  struct P5_Session *session = handle;
489141cc406Sopenharmony_ci
490141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_option_descriptor: start\n");
491141cc406Sopenharmony_ci
492141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
493141cc406Sopenharmony_ci    return NULL;
494141cc406Sopenharmony_ci
495141cc406Sopenharmony_ci  DBG (DBG_info, "sane_get_option_descriptor: \"%s\"\n",
496141cc406Sopenharmony_ci       session->options[option].descriptor.name);
497141cc406Sopenharmony_ci
498141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_option_descriptor: exit\n");
499141cc406Sopenharmony_ci  return &(session->options[option].descriptor);
500141cc406Sopenharmony_ci}
501141cc406Sopenharmony_ci
502141cc406Sopenharmony_ci/**
503141cc406Sopenharmony_ci * sets automatic value for an option , called by sane_control_option after
504141cc406Sopenharmony_ci * all checks have been done */
505141cc406Sopenharmony_cistatic SANE_Status
506141cc406Sopenharmony_ciset_automatic_value (P5_Session * s, int option, SANE_Int * myinfo)
507141cc406Sopenharmony_ci{
508141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
509141cc406Sopenharmony_ci  SANE_Int i, min;
510141cc406Sopenharmony_ci  SANE_Word *dpi_list;
511141cc406Sopenharmony_ci
512141cc406Sopenharmony_ci  switch (option)
513141cc406Sopenharmony_ci    {
514141cc406Sopenharmony_ci    case OPT_TL_X:
515141cc406Sopenharmony_ci      s->options[OPT_TL_X].value.w = x_range.min;
516141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
517141cc406Sopenharmony_ci      break;
518141cc406Sopenharmony_ci    case OPT_TL_Y:
519141cc406Sopenharmony_ci      s->options[OPT_TL_Y].value.w = y_range.min;
520141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
521141cc406Sopenharmony_ci      break;
522141cc406Sopenharmony_ci    case OPT_BR_X:
523141cc406Sopenharmony_ci      s->options[OPT_BR_X].value.w = x_range.max;
524141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
525141cc406Sopenharmony_ci      break;
526141cc406Sopenharmony_ci    case OPT_BR_Y:
527141cc406Sopenharmony_ci      s->options[OPT_BR_Y].value.w = y_range.max;
528141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
529141cc406Sopenharmony_ci      break;
530141cc406Sopenharmony_ci    case OPT_RESOLUTION:
531141cc406Sopenharmony_ci      /* we set up to the lowest available dpi value */
532141cc406Sopenharmony_ci      dpi_list =
533141cc406Sopenharmony_ci	(SANE_Word *) s->options[OPT_RESOLUTION].descriptor.constraint.
534141cc406Sopenharmony_ci	word_list;
535141cc406Sopenharmony_ci      min = 65536;
536141cc406Sopenharmony_ci      for (i = 1; i < dpi_list[0]; i++)
537141cc406Sopenharmony_ci	{
538141cc406Sopenharmony_ci	  if (dpi_list[i] < min)
539141cc406Sopenharmony_ci	    min = dpi_list[i];
540141cc406Sopenharmony_ci	}
541141cc406Sopenharmony_ci      s->options[OPT_RESOLUTION].value.w = min;
542141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
543141cc406Sopenharmony_ci      break;
544141cc406Sopenharmony_ci    case OPT_PREVIEW:
545141cc406Sopenharmony_ci      s->options[OPT_PREVIEW].value.w = SANE_FALSE;
546141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
547141cc406Sopenharmony_ci      break;
548141cc406Sopenharmony_ci    case OPT_MODE:
549141cc406Sopenharmony_ci      if (s->options[OPT_MODE].value.s)
550141cc406Sopenharmony_ci	free (s->options[OPT_MODE].value.s);
551141cc406Sopenharmony_ci      s->options[OPT_MODE].value.s = strdup (mode_list[0]);
552141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_OPTIONS;
553141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
554141cc406Sopenharmony_ci      break;
555141cc406Sopenharmony_ci    default:
556141cc406Sopenharmony_ci      DBG (DBG_warn, "set_automatic_value: can't set unknown option %d\n",
557141cc406Sopenharmony_ci	   option);
558141cc406Sopenharmony_ci    }
559141cc406Sopenharmony_ci
560141cc406Sopenharmony_ci  return status;
561141cc406Sopenharmony_ci}
562141cc406Sopenharmony_ci
563141cc406Sopenharmony_ci/**
564141cc406Sopenharmony_ci * sets an option , called by sane_control_option after all
565141cc406Sopenharmony_ci * checks have been done */
566141cc406Sopenharmony_cistatic SANE_Status
567141cc406Sopenharmony_ciset_option_value (P5_Session * s, int option, void *val, SANE_Int * myinfo)
568141cc406Sopenharmony_ci{
569141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
570141cc406Sopenharmony_ci  SANE_Word tmpw;
571141cc406Sopenharmony_ci
572141cc406Sopenharmony_ci  switch (option)
573141cc406Sopenharmony_ci    {
574141cc406Sopenharmony_ci    case OPT_TL_X:
575141cc406Sopenharmony_ci    case OPT_BR_X:
576141cc406Sopenharmony_ci    case OPT_TL_Y:
577141cc406Sopenharmony_ci    case OPT_BR_Y:
578141cc406Sopenharmony_ci      s->options[option].value.w = *(SANE_Word *) val;
579141cc406Sopenharmony_ci      /* we ensure geometry is coherent */
580141cc406Sopenharmony_ci      /* this happens when user drags TL corner right or below the BR point */
581141cc406Sopenharmony_ci      if (s->options[OPT_BR_Y].value.w < s->options[OPT_TL_Y].value.w)
582141cc406Sopenharmony_ci	{
583141cc406Sopenharmony_ci	  tmpw = s->options[OPT_BR_Y].value.w;
584141cc406Sopenharmony_ci	  s->options[OPT_BR_Y].value.w = s->options[OPT_TL_Y].value.w;
585141cc406Sopenharmony_ci	  s->options[OPT_TL_Y].value.w = tmpw;
586141cc406Sopenharmony_ci	}
587141cc406Sopenharmony_ci      if (s->options[OPT_BR_X].value.w < s->options[OPT_TL_X].value.w)
588141cc406Sopenharmony_ci	{
589141cc406Sopenharmony_ci	  tmpw = s->options[OPT_BR_X].value.w;
590141cc406Sopenharmony_ci	  s->options[OPT_BR_X].value.w = s->options[OPT_TL_X].value.w;
591141cc406Sopenharmony_ci	  s->options[OPT_TL_X].value.w = tmpw;
592141cc406Sopenharmony_ci	}
593141cc406Sopenharmony_ci
594141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
595141cc406Sopenharmony_ci      break;
596141cc406Sopenharmony_ci
597141cc406Sopenharmony_ci    case OPT_RESOLUTION:
598141cc406Sopenharmony_ci    case OPT_PREVIEW:
599141cc406Sopenharmony_ci      s->options[option].value.w = *(SANE_Word *) val;
600141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS;
601141cc406Sopenharmony_ci      break;
602141cc406Sopenharmony_ci
603141cc406Sopenharmony_ci    case OPT_MODE:
604141cc406Sopenharmony_ci      if (s->options[option].value.s)
605141cc406Sopenharmony_ci	free (s->options[option].value.s);
606141cc406Sopenharmony_ci      s->options[option].value.s = strdup (val);
607141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
608141cc406Sopenharmony_ci      break;
609141cc406Sopenharmony_ci
610141cc406Sopenharmony_ci    case OPT_CALIBRATE:
611141cc406Sopenharmony_ci      status = sheetfed_calibration (s->dev);
612141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_OPTIONS;
613141cc406Sopenharmony_ci      break;
614141cc406Sopenharmony_ci
615141cc406Sopenharmony_ci    case OPT_CLEAR_CALIBRATION:
616141cc406Sopenharmony_ci      cleanup_calibration (s->dev);
617141cc406Sopenharmony_ci      *myinfo |= SANE_INFO_RELOAD_OPTIONS;
618141cc406Sopenharmony_ci      break;
619141cc406Sopenharmony_ci
620141cc406Sopenharmony_ci    default:
621141cc406Sopenharmony_ci      DBG (DBG_warn, "set_option_value: can't set unknown option %d\n",
622141cc406Sopenharmony_ci	   option);
623141cc406Sopenharmony_ci    }
624141cc406Sopenharmony_ci  return status;
625141cc406Sopenharmony_ci}
626141cc406Sopenharmony_ci
627141cc406Sopenharmony_ci/**
628141cc406Sopenharmony_ci * gets an option , called by sane_control_option after all checks
629141cc406Sopenharmony_ci * have been done */
630141cc406Sopenharmony_cistatic SANE_Status
631141cc406Sopenharmony_ciget_option_value (P5_Session * s, int option, void *val)
632141cc406Sopenharmony_ci{
633141cc406Sopenharmony_ci  SANE_Status status;
634141cc406Sopenharmony_ci
635141cc406Sopenharmony_ci  switch (option)
636141cc406Sopenharmony_ci    {
637141cc406Sopenharmony_ci      /* word or word equivalent options: */
638141cc406Sopenharmony_ci    case OPT_NUM_OPTS:
639141cc406Sopenharmony_ci    case OPT_RESOLUTION:
640141cc406Sopenharmony_ci    case OPT_PREVIEW:
641141cc406Sopenharmony_ci    case OPT_TL_X:
642141cc406Sopenharmony_ci    case OPT_TL_Y:
643141cc406Sopenharmony_ci    case OPT_BR_X:
644141cc406Sopenharmony_ci    case OPT_BR_Y:
645141cc406Sopenharmony_ci      *(SANE_Word *) val = s->options[option].value.w;
646141cc406Sopenharmony_ci      break;
647141cc406Sopenharmony_ci
648141cc406Sopenharmony_ci      /* string options: */
649141cc406Sopenharmony_ci    case OPT_MODE:
650141cc406Sopenharmony_ci      strcpy (val, s->options[option].value.s);
651141cc406Sopenharmony_ci      break;
652141cc406Sopenharmony_ci
653141cc406Sopenharmony_ci      /* sensor options */
654141cc406Sopenharmony_ci    case OPT_PAGE_LOADED_SW:
655141cc406Sopenharmony_ci      status = test_document (s->dev->fd);
656141cc406Sopenharmony_ci      if (status == SANE_STATUS_GOOD)
657141cc406Sopenharmony_ci	s->options[option].value.b = SANE_TRUE;
658141cc406Sopenharmony_ci      else
659141cc406Sopenharmony_ci	s->options[option].value.b = SANE_FALSE;
660141cc406Sopenharmony_ci      *(SANE_Bool *) val = s->options[option].value.b;
661141cc406Sopenharmony_ci      break;
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci    case OPT_NEED_CALIBRATION_SW:
664141cc406Sopenharmony_ci      *(SANE_Bool *) val = !s->dev->calibrated;
665141cc406Sopenharmony_ci      break;
666141cc406Sopenharmony_ci
667141cc406Sopenharmony_ci
668141cc406Sopenharmony_ci      /* unhandled options */
669141cc406Sopenharmony_ci    default:
670141cc406Sopenharmony_ci      DBG (DBG_warn, "get_option_value: can't get unknown option %d\n",
671141cc406Sopenharmony_ci	   option);
672141cc406Sopenharmony_ci    }
673141cc406Sopenharmony_ci
674141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
675141cc406Sopenharmony_ci}
676141cc406Sopenharmony_ci
677141cc406Sopenharmony_ci/**
678141cc406Sopenharmony_ci * Gets or sets an option value.
679141cc406Sopenharmony_ci *
680141cc406Sopenharmony_ci * From the SANE spec:
681141cc406Sopenharmony_ci * This function is used to set or inquire the current value of option
682141cc406Sopenharmony_ci * number n of the device represented by handle h. The manner in which
683141cc406Sopenharmony_ci * the option is controlled is specified by parameter action. The
684141cc406Sopenharmony_ci * possible values of this parameter are described in more detail
685141cc406Sopenharmony_ci * below.  The value of the option is passed through argument val. It
686141cc406Sopenharmony_ci * is a pointer to the memory that holds the option value. The memory
687141cc406Sopenharmony_ci * area pointed to by v must be big enough to hold the entire option
688141cc406Sopenharmony_ci * value (determined by member size in the corresponding option
689141cc406Sopenharmony_ci * descriptor).
690141cc406Sopenharmony_ci *
691141cc406Sopenharmony_ci * The only exception to this rule is that when setting the value of a
692141cc406Sopenharmony_ci * string option, the string pointed to by argument v may be shorter
693141cc406Sopenharmony_ci * since the backend will stop reading the option value upon
694141cc406Sopenharmony_ci * encountering the first NUL terminator in the string. If argument i
695141cc406Sopenharmony_ci * is not NULL, the value of *i will be set to provide details on how
696141cc406Sopenharmony_ci * well the request has been met.
697141cc406Sopenharmony_ci * action is SANE_ACTION_GET_VALUE, SANE_ACTION_SET_VALUE or SANE_ACTION_SET_AUTO
698141cc406Sopenharmony_ci */
699141cc406Sopenharmony_ciSANE_Status
700141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
701141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
702141cc406Sopenharmony_ci{
703141cc406Sopenharmony_ci  P5_Session *s = handle;
704141cc406Sopenharmony_ci  SANE_Status status;
705141cc406Sopenharmony_ci  SANE_Word cap;
706141cc406Sopenharmony_ci  SANE_Int myinfo = 0;
707141cc406Sopenharmony_ci
708141cc406Sopenharmony_ci  DBG (DBG_io2,
709141cc406Sopenharmony_ci       "sane_control_option: start: action = %s, option = %s (%d)\n",
710141cc406Sopenharmony_ci       (action == SANE_ACTION_GET_VALUE) ? "get" : (action ==
711141cc406Sopenharmony_ci						    SANE_ACTION_SET_VALUE) ?
712141cc406Sopenharmony_ci       "set" : (action == SANE_ACTION_SET_AUTO) ? "set_auto" : "unknown",
713141cc406Sopenharmony_ci       s->options[option].descriptor.name, option);
714141cc406Sopenharmony_ci
715141cc406Sopenharmony_ci  if (info)
716141cc406Sopenharmony_ci    *info = 0;
717141cc406Sopenharmony_ci
718141cc406Sopenharmony_ci  /* do checks before trying to apply action */
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci  if (s->scanning)
721141cc406Sopenharmony_ci    {
722141cc406Sopenharmony_ci      DBG (DBG_warn, "sane_control_option: don't call this function while "
723141cc406Sopenharmony_ci	   "scanning (option = %s (%d))\n",
724141cc406Sopenharmony_ci	   s->options[option].descriptor.name, option);
725141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
726141cc406Sopenharmony_ci    }
727141cc406Sopenharmony_ci
728141cc406Sopenharmony_ci  /* option must be within existing range */
729141cc406Sopenharmony_ci  if (option >= NUM_OPTIONS || option < 0)
730141cc406Sopenharmony_ci    {
731141cc406Sopenharmony_ci      DBG (DBG_warn,
732141cc406Sopenharmony_ci	   "sane_control_option: option %d >= NUM_OPTIONS || option < 0\n",
733141cc406Sopenharmony_ci	   option);
734141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
735141cc406Sopenharmony_ci    }
736141cc406Sopenharmony_ci
737141cc406Sopenharmony_ci  /* don't access an inactive option */
738141cc406Sopenharmony_ci  cap = s->options[option].descriptor.cap;
739141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
740141cc406Sopenharmony_ci    {
741141cc406Sopenharmony_ci      DBG (DBG_warn, "sane_control_option: option %d is inactive\n", option);
742141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
743141cc406Sopenharmony_ci    }
744141cc406Sopenharmony_ci
745141cc406Sopenharmony_ci  /* now checks have been done, apply action */
746141cc406Sopenharmony_ci  switch (action)
747141cc406Sopenharmony_ci    {
748141cc406Sopenharmony_ci    case SANE_ACTION_GET_VALUE:
749141cc406Sopenharmony_ci      status = get_option_value (s, option, val);
750141cc406Sopenharmony_ci      break;
751141cc406Sopenharmony_ci
752141cc406Sopenharmony_ci    case SANE_ACTION_SET_VALUE:
753141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
754141cc406Sopenharmony_ci	{
755141cc406Sopenharmony_ci	  DBG (DBG_warn, "sane_control_option: option %d is not settable\n",
756141cc406Sopenharmony_ci	       option);
757141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
758141cc406Sopenharmony_ci	}
759141cc406Sopenharmony_ci
760141cc406Sopenharmony_ci      status =
761141cc406Sopenharmony_ci	sanei_constrain_value (&s->options[option].descriptor, val, &myinfo);
762141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
763141cc406Sopenharmony_ci	{
764141cc406Sopenharmony_ci	  DBG (DBG_warn,
765141cc406Sopenharmony_ci	       "sane_control_option: sanei_constrain_value returned %s\n",
766141cc406Sopenharmony_ci	       sane_strstatus (status));
767141cc406Sopenharmony_ci	  return status;
768141cc406Sopenharmony_ci	}
769141cc406Sopenharmony_ci
770141cc406Sopenharmony_ci      /* return immediately if no change */
771141cc406Sopenharmony_ci      if (s->options[option].descriptor.type == SANE_TYPE_INT
772141cc406Sopenharmony_ci	  && *(SANE_Word *) val == s->options[option].value.w)
773141cc406Sopenharmony_ci	{
774141cc406Sopenharmony_ci	  status = SANE_STATUS_GOOD;
775141cc406Sopenharmony_ci	}
776141cc406Sopenharmony_ci      else
777141cc406Sopenharmony_ci	{			/* apply change */
778141cc406Sopenharmony_ci	  status = set_option_value (s, option, val, &myinfo);
779141cc406Sopenharmony_ci	}
780141cc406Sopenharmony_ci      break;
781141cc406Sopenharmony_ci
782141cc406Sopenharmony_ci    case SANE_ACTION_SET_AUTO:
783141cc406Sopenharmony_ci      /* sets automatic values */
784141cc406Sopenharmony_ci      if (!(cap & SANE_CAP_AUTOMATIC))
785141cc406Sopenharmony_ci	{
786141cc406Sopenharmony_ci	  DBG (DBG_warn,
787141cc406Sopenharmony_ci	       "sane_control_option: option %d is not autosettable\n",
788141cc406Sopenharmony_ci	       option);
789141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
790141cc406Sopenharmony_ci	}
791141cc406Sopenharmony_ci
792141cc406Sopenharmony_ci      status = set_automatic_value (s, option, &myinfo);
793141cc406Sopenharmony_ci      break;
794141cc406Sopenharmony_ci
795141cc406Sopenharmony_ci    default:
796141cc406Sopenharmony_ci      DBG (DBG_error, "sane_control_option: invalid action %d\n", action);
797141cc406Sopenharmony_ci      status = SANE_STATUS_INVAL;
798141cc406Sopenharmony_ci      break;
799141cc406Sopenharmony_ci    }
800141cc406Sopenharmony_ci
801141cc406Sopenharmony_ci  if (info)
802141cc406Sopenharmony_ci    *info = myinfo;
803141cc406Sopenharmony_ci
804141cc406Sopenharmony_ci  DBG (DBG_io2, "sane_control_option: exit\n");
805141cc406Sopenharmony_ci  return status;
806141cc406Sopenharmony_ci}
807141cc406Sopenharmony_ci
808141cc406Sopenharmony_ci/**
809141cc406Sopenharmony_ci * Called by SANE when a page acquisition operation is to be started.
810141cc406Sopenharmony_ci * @param handle opaque handle to a frontend session
811141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD on success, SANE_STATUS_BUSY if the device is
812141cc406Sopenharmony_ci * in use by another session or SANE_STATUS_WARMING_UP if the device is
813141cc406Sopenharmony_ci * warming up. In this case the fronted as to call sane_start again until
814141cc406Sopenharmony_ci * warming up is done. Any other values returned are error status.
815141cc406Sopenharmony_ci */
816141cc406Sopenharmony_ciSANE_Status
817141cc406Sopenharmony_cisane_start (SANE_Handle handle)
818141cc406Sopenharmony_ci{
819141cc406Sopenharmony_ci  struct P5_Session *session = handle;
820141cc406Sopenharmony_ci  int status = SANE_STATUS_GOOD;
821141cc406Sopenharmony_ci  P5_Device *dev = session->dev;
822141cc406Sopenharmony_ci
823141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: start\n");
824141cc406Sopenharmony_ci
825141cc406Sopenharmony_ci  /* if already scanning, tell we're busy */
826141cc406Sopenharmony_ci  if (session->scanning == SANE_TRUE)
827141cc406Sopenharmony_ci    {
828141cc406Sopenharmony_ci      DBG (DBG_info, "sane_start: device is already scanning\n");
829141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
830141cc406Sopenharmony_ci    }
831141cc406Sopenharmony_ci
832141cc406Sopenharmony_ci  /* check that the device has been initialized */
833141cc406Sopenharmony_ci  if (dev->initialized == SANE_FALSE)
834141cc406Sopenharmony_ci    {
835141cc406Sopenharmony_ci      DBG (DBG_error, "sane_start: device is not initialized\n");
836141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
837141cc406Sopenharmony_ci    }
838141cc406Sopenharmony_ci
839141cc406Sopenharmony_ci  /* check if there is a document */
840141cc406Sopenharmony_ci  status = test_document (dev->fd);
841141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
842141cc406Sopenharmony_ci    {
843141cc406Sopenharmony_ci      DBG (DBG_error, "sane_start: device is already scanning\n");
844141cc406Sopenharmony_ci      return status;
845141cc406Sopenharmony_ci    }
846141cc406Sopenharmony_ci
847141cc406Sopenharmony_ci  /* we compute all the scan parameters so that */
848141cc406Sopenharmony_ci  /* we will be able to set up the registers correctly */
849141cc406Sopenharmony_ci  compute_parameters (session);
850141cc406Sopenharmony_ci
851141cc406Sopenharmony_ci  /* move to scan area if needed */
852141cc406Sopenharmony_ci  if (dev->ystart > 0)
853141cc406Sopenharmony_ci    {
854141cc406Sopenharmony_ci      status = move (dev);
855141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
856141cc406Sopenharmony_ci	{
857141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_start: failed to move to scan area\n");
858141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
859141cc406Sopenharmony_ci	}
860141cc406Sopenharmony_ci    }
861141cc406Sopenharmony_ci
862141cc406Sopenharmony_ci  /* send scan command */
863141cc406Sopenharmony_ci  status = start_scan (dev, dev->mode, dev->ydpi, dev->xstart, dev->pixels);
864141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
865141cc406Sopenharmony_ci    {
866141cc406Sopenharmony_ci      DBG (DBG_error, "sane_start: failed to start scan\n");
867141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
868141cc406Sopenharmony_ci    }
869141cc406Sopenharmony_ci
870141cc406Sopenharmony_ci  /* allocates work buffer */
871141cc406Sopenharmony_ci  if (dev->buffer != NULL)
872141cc406Sopenharmony_ci    {
873141cc406Sopenharmony_ci      free (dev->buffer);
874141cc406Sopenharmony_ci    }
875141cc406Sopenharmony_ci
876141cc406Sopenharmony_ci  dev->position = 0;
877141cc406Sopenharmony_ci  dev->top = 0;
878141cc406Sopenharmony_ci  /* compute amount of lines needed for lds correction */
879141cc406Sopenharmony_ci  dev->bottom = dev->bytes_per_line * 2 * dev->lds;
880141cc406Sopenharmony_ci  /* computes buffer size, 66 color lines plus eventual amount needed for lds */
881141cc406Sopenharmony_ci  dev->size = dev->pixels * 3 * 66 + dev->bottom;
882141cc406Sopenharmony_ci  dev->buffer = (uint8_t *) malloc (dev->size);
883141cc406Sopenharmony_ci  if (dev->buffer == NULL)
884141cc406Sopenharmony_ci    {
885141cc406Sopenharmony_ci      DBG (DBG_error, "sane_start: failed to allocate %lu bytes\n", (unsigned long)dev->size);
886141cc406Sopenharmony_ci      sane_cancel (handle);
887141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
888141cc406Sopenharmony_ci    }
889141cc406Sopenharmony_ci
890141cc406Sopenharmony_ci  /* return now the scan has been initiated */
891141cc406Sopenharmony_ci  session->scanning = SANE_TRUE;
892141cc406Sopenharmony_ci  session->sent = 0;
893141cc406Sopenharmony_ci
894141cc406Sopenharmony_ci  DBG (DBG_io, "sane_start: to_send=%d\n", session->to_send);
895141cc406Sopenharmony_ci  DBG (DBG_io, "sane_start: size=%lu\n", (unsigned long)dev->size);
896141cc406Sopenharmony_ci  DBG (DBG_io, "sane_start: top=%lu\n", (unsigned long)dev->top);
897141cc406Sopenharmony_ci  DBG (DBG_io, "sane_start: bottom=%lu\n", (unsigned long)dev->bottom);
898141cc406Sopenharmony_ci  DBG (DBG_io, "sane_start: position=%lu\n", (unsigned long)dev->position);
899141cc406Sopenharmony_ci
900141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: exit\n");
901141cc406Sopenharmony_ci  return status;
902141cc406Sopenharmony_ci}
903141cc406Sopenharmony_ci
904141cc406Sopenharmony_ci/** @brief compute scan parameters
905141cc406Sopenharmony_ci * This function computes two set of parameters. The one for the SANE's standard
906141cc406Sopenharmony_ci * and the other for the hardware. Among these parameters are the bit depth, total
907141cc406Sopenharmony_ci * number of lines, total number of columns, extra line to read for data reordering...
908141cc406Sopenharmony_ci * @param session fronted session to compute final scan parameters
909141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD on success
910141cc406Sopenharmony_ci */
911141cc406Sopenharmony_cistatic SANE_Status
912141cc406Sopenharmony_cicompute_parameters (P5_Session * session)
913141cc406Sopenharmony_ci{
914141cc406Sopenharmony_ci  P5_Device *dev = session->dev;
915141cc406Sopenharmony_ci  SANE_Int dpi;			/* dpi for scan */
916141cc406Sopenharmony_ci  SANE_String mode;
917141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
918141cc406Sopenharmony_ci
919141cc406Sopenharmony_ci  int tl_x, tl_y, br_x, br_y;
920141cc406Sopenharmony_ci
921141cc406Sopenharmony_ci  mode = session->options[OPT_MODE].value.s;
922141cc406Sopenharmony_ci  dpi = session->options[OPT_RESOLUTION].value.w;
923141cc406Sopenharmony_ci
924141cc406Sopenharmony_ci  /* scan coordinates */
925141cc406Sopenharmony_ci  tl_x = SANE_UNFIX (session->options[OPT_TL_X].value.w);
926141cc406Sopenharmony_ci  tl_y = SANE_UNFIX (session->options[OPT_TL_Y].value.w);
927141cc406Sopenharmony_ci  br_x = SANE_UNFIX (session->options[OPT_BR_X].value.w);
928141cc406Sopenharmony_ci  br_y = SANE_UNFIX (session->options[OPT_BR_Y].value.w);
929141cc406Sopenharmony_ci
930141cc406Sopenharmony_ci  /* only single pass scanning supported */
931141cc406Sopenharmony_ci  session->params.last_frame = SANE_TRUE;
932141cc406Sopenharmony_ci
933141cc406Sopenharmony_ci  /* gray modes */
934141cc406Sopenharmony_ci  if (strcmp (mode, GRAY_MODE) == 0)
935141cc406Sopenharmony_ci    {
936141cc406Sopenharmony_ci      session->params.format = SANE_FRAME_GRAY;
937141cc406Sopenharmony_ci      dev->mode = MODE_GRAY;
938141cc406Sopenharmony_ci      dev->lds = 0;
939141cc406Sopenharmony_ci    }
940141cc406Sopenharmony_ci  else if (strcmp (mode, LINEART_MODE) == 0)
941141cc406Sopenharmony_ci    {
942141cc406Sopenharmony_ci      session->params.format = SANE_FRAME_GRAY;
943141cc406Sopenharmony_ci      dev->mode = MODE_LINEART;
944141cc406Sopenharmony_ci      dev->lds = 0;
945141cc406Sopenharmony_ci    }
946141cc406Sopenharmony_ci  else
947141cc406Sopenharmony_ci    {
948141cc406Sopenharmony_ci      /* Color */
949141cc406Sopenharmony_ci      session->params.format = SANE_FRAME_RGB;
950141cc406Sopenharmony_ci      dev->mode = MODE_COLOR;
951141cc406Sopenharmony_ci      dev->lds = (dev->model->lds * dpi) / dev->model->max_ydpi;
952141cc406Sopenharmony_ci    }
953141cc406Sopenharmony_ci
954141cc406Sopenharmony_ci  /* SANE level values */
955141cc406Sopenharmony_ci  session->params.lines = ((br_y - tl_y) * dpi) / MM_PER_INCH;
956141cc406Sopenharmony_ci  if (session->params.lines == 0)
957141cc406Sopenharmony_ci    session->params.lines = 1;
958141cc406Sopenharmony_ci  session->params.pixels_per_line = ((br_x - tl_x) * dpi) / MM_PER_INCH;
959141cc406Sopenharmony_ci  if (session->params.pixels_per_line == 0)
960141cc406Sopenharmony_ci    session->params.pixels_per_line = 1;
961141cc406Sopenharmony_ci
962141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: pixels_per_line   =%d\n",
963141cc406Sopenharmony_ci       session->params.pixels_per_line);
964141cc406Sopenharmony_ci
965141cc406Sopenharmony_ci  if (strcmp (mode, LINEART_MODE) == 0)
966141cc406Sopenharmony_ci    {
967141cc406Sopenharmony_ci      session->params.depth = 1;
968141cc406Sopenharmony_ci      /* in lineart, having pixels multiple of 8 avoids a costly test */
969141cc406Sopenharmony_ci      /* at each bit to see we must go to the next byte               */
970141cc406Sopenharmony_ci      /* TODO : implement this requirement in sane_control_option */
971141cc406Sopenharmony_ci      session->params.pixels_per_line =
972141cc406Sopenharmony_ci	((session->params.pixels_per_line + 7) / 8) * 8;
973141cc406Sopenharmony_ci    }
974141cc406Sopenharmony_ci  else
975141cc406Sopenharmony_ci    session->params.depth = 8;
976141cc406Sopenharmony_ci
977141cc406Sopenharmony_ci  /* width needs to be even */
978141cc406Sopenharmony_ci  if (session->params.pixels_per_line & 1)
979141cc406Sopenharmony_ci    session->params.pixels_per_line++;
980141cc406Sopenharmony_ci
981141cc406Sopenharmony_ci  /* Hardware settings : they can differ from the ones at SANE level */
982141cc406Sopenharmony_ci  /* for instance the effective DPI used by a sensor may be higher   */
983141cc406Sopenharmony_ci  /* than the one needed for the SANE scan parameters                */
984141cc406Sopenharmony_ci  dev->lines = session->params.lines;
985141cc406Sopenharmony_ci  dev->pixels = session->params.pixels_per_line;
986141cc406Sopenharmony_ci
987141cc406Sopenharmony_ci  /* motor and sensor DPI */
988141cc406Sopenharmony_ci  dev->xdpi = dpi;
989141cc406Sopenharmony_ci  dev->ydpi = dpi;
990141cc406Sopenharmony_ci
991141cc406Sopenharmony_ci  /* handle bounds of motor's dpi range */
992141cc406Sopenharmony_ci  if (dev->ydpi > dev->model->max_ydpi)
993141cc406Sopenharmony_ci    {
994141cc406Sopenharmony_ci      dev->ydpi = dev->model->max_ydpi;
995141cc406Sopenharmony_ci      dev->lines = (dev->lines * dev->model->max_ydpi) / dpi;
996141cc406Sopenharmony_ci      if (dev->lines == 0)
997141cc406Sopenharmony_ci	dev->lines = 1;
998141cc406Sopenharmony_ci
999141cc406Sopenharmony_ci      /* round number of lines */
1000141cc406Sopenharmony_ci      session->params.lines =
1001141cc406Sopenharmony_ci	(session->params.lines / dev->lines) * dev->lines;
1002141cc406Sopenharmony_ci      if (session->params.lines == 0)
1003141cc406Sopenharmony_ci	session->params.lines = 1;
1004141cc406Sopenharmony_ci    }
1005141cc406Sopenharmony_ci  if (dev->ydpi < dev->model->min_ydpi)
1006141cc406Sopenharmony_ci    {
1007141cc406Sopenharmony_ci      dev->ydpi = dev->model->min_ydpi;
1008141cc406Sopenharmony_ci      dev->lines = (dev->lines * dev->model->min_ydpi) / dpi;
1009141cc406Sopenharmony_ci    }
1010141cc406Sopenharmony_ci
1011141cc406Sopenharmony_ci  /* hardware values */
1012141cc406Sopenharmony_ci  dev->xstart =
1013141cc406Sopenharmony_ci    ((SANE_UNFIX (dev->model->x_offset) + tl_x) * dpi) / MM_PER_INCH;
1014141cc406Sopenharmony_ci  dev->ystart =
1015141cc406Sopenharmony_ci    ((SANE_UNFIX (dev->model->y_offset) + tl_y) * dev->ydpi) / MM_PER_INCH;
1016141cc406Sopenharmony_ci
1017141cc406Sopenharmony_ci  /* take lds correction into account when moving to scan area */
1018141cc406Sopenharmony_ci  if (dev->ystart > 2 * dev->lds)
1019141cc406Sopenharmony_ci    dev->ystart -= 2 * dev->lds;
1020141cc406Sopenharmony_ci
1021141cc406Sopenharmony_ci
1022141cc406Sopenharmony_ci  /* computes bytes per line */
1023141cc406Sopenharmony_ci  session->params.bytes_per_line = session->params.pixels_per_line;
1024141cc406Sopenharmony_ci  dev->bytes_per_line = dev->pixels;
1025141cc406Sopenharmony_ci  if (session->params.format == SANE_FRAME_RGB)
1026141cc406Sopenharmony_ci    {
1027141cc406Sopenharmony_ci      dev->bytes_per_line *= 3;
1028141cc406Sopenharmony_ci    }
1029141cc406Sopenharmony_ci
1030141cc406Sopenharmony_ci  /* in lineart mode we adjust bytes_per_line needed by frontend */
1031141cc406Sopenharmony_ci  /* we do that here because we needed sent/to_send to be as if  */
1032141cc406Sopenharmony_ci  /* there was no lineart                                        */
1033141cc406Sopenharmony_ci  if (session->params.depth == 1)
1034141cc406Sopenharmony_ci    {
1035141cc406Sopenharmony_ci      session->params.bytes_per_line =
1036141cc406Sopenharmony_ci	(session->params.bytes_per_line + 7) / 8;
1037141cc406Sopenharmony_ci    }
1038141cc406Sopenharmony_ci
1039141cc406Sopenharmony_ci  session->params.bytes_per_line = dev->bytes_per_line;
1040141cc406Sopenharmony_ci  session->to_send = session->params.bytes_per_line * session->params.lines;
1041141cc406Sopenharmony_ci  session->params.bytes_per_line = dev->bytes_per_line;
1042141cc406Sopenharmony_ci
1043141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: bytes_per_line    =%d\n",
1044141cc406Sopenharmony_ci       session->params.bytes_per_line);
1045141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: depth             =%d\n",
1046141cc406Sopenharmony_ci       session->params.depth);
1047141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: lines             =%d\n",
1048141cc406Sopenharmony_ci       session->params.lines);
1049141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: image size        =%d\n",
1050141cc406Sopenharmony_ci       session->to_send);
1051141cc406Sopenharmony_ci
1052141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: xstart            =%d\n", dev->xstart);
1053141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: ystart            =%d\n", dev->ystart);
1054141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: dev lines         =%d\n", dev->lines);
1055141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: dev bytes per line=%d\n",
1056141cc406Sopenharmony_ci       dev->bytes_per_line);
1057141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: dev pixels        =%d\n", dev->pixels);
1058141cc406Sopenharmony_ci  DBG (DBG_data, "compute_parameters: lds               =%d\n", dev->lds);
1059141cc406Sopenharmony_ci
1060141cc406Sopenharmony_ci  return status;
1061141cc406Sopenharmony_ci}
1062141cc406Sopenharmony_ci
1063141cc406Sopenharmony_ci
1064141cc406Sopenharmony_ci/**
1065141cc406Sopenharmony_ci * Called by SANE to retrieve information about the type of data
1066141cc406Sopenharmony_ci * that the current scan will return.
1067141cc406Sopenharmony_ci *
1068141cc406Sopenharmony_ci * From the SANE spec:
1069141cc406Sopenharmony_ci * This function is used to obtain the current scan parameters. The
1070141cc406Sopenharmony_ci * returned parameters are guaranteed to be accurate between the time
1071141cc406Sopenharmony_ci * a scan has been started (sane_start() has been called) and the
1072141cc406Sopenharmony_ci * completion of that request. Outside of that window, the returned
1073141cc406Sopenharmony_ci * values are best-effort estimates of what the parameters will be
1074141cc406Sopenharmony_ci * when sane_start() gets invoked.
1075141cc406Sopenharmony_ci *
1076141cc406Sopenharmony_ci * Calling this function before a scan has actually started allows,
1077141cc406Sopenharmony_ci * for example, to get an estimate of how big the scanned image will
1078141cc406Sopenharmony_ci * be. The parameters passed to this function are the handle of the
1079141cc406Sopenharmony_ci * device for which the parameters should be obtained and a pointer
1080141cc406Sopenharmony_ci * to a parameter structure.
1081141cc406Sopenharmony_ci */
1082141cc406Sopenharmony_ciSANE_Status
1083141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
1084141cc406Sopenharmony_ci{
1085141cc406Sopenharmony_ci  SANE_Status status;
1086141cc406Sopenharmony_ci  struct P5_Session *session = (struct P5_Session *) handle;
1087141cc406Sopenharmony_ci
1088141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_parameters: start\n");
1089141cc406Sopenharmony_ci
1090141cc406Sopenharmony_ci  /* call parameters computing function */
1091141cc406Sopenharmony_ci  status = compute_parameters (session);
1092141cc406Sopenharmony_ci  if (status == SANE_STATUS_GOOD && params)
1093141cc406Sopenharmony_ci    *params = session->params;
1094141cc406Sopenharmony_ci
1095141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_parameters: exit\n");
1096141cc406Sopenharmony_ci  return status;
1097141cc406Sopenharmony_ci}
1098141cc406Sopenharmony_ci
1099141cc406Sopenharmony_ci
1100141cc406Sopenharmony_ci/**
1101141cc406Sopenharmony_ci * Called by SANE to read data.
1102141cc406Sopenharmony_ci *
1103141cc406Sopenharmony_ci * From the SANE spec:
1104141cc406Sopenharmony_ci * This function is used to read image data from the device
1105141cc406Sopenharmony_ci * represented by handle h.  Argument buf is a pointer to a memory
1106141cc406Sopenharmony_ci * area that is at least maxlen bytes long.  The number of bytes
1107141cc406Sopenharmony_ci * returned is stored in *len. A backend must set this to zero when
1108141cc406Sopenharmony_ci * the call fails (i.e., when a status other than SANE_STATUS_GOOD is
1109141cc406Sopenharmony_ci * returned).
1110141cc406Sopenharmony_ci *
1111141cc406Sopenharmony_ci * When the call succeeds, the number of bytes returned can be
1112141cc406Sopenharmony_ci * anywhere in the range from 0 to maxlen bytes.
1113141cc406Sopenharmony_ci *
1114141cc406Sopenharmony_ci * Returned data is read from working buffer.
1115141cc406Sopenharmony_ci */
1116141cc406Sopenharmony_ciSANE_Status
1117141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf,
1118141cc406Sopenharmony_ci	   SANE_Int max_len, SANE_Int * len)
1119141cc406Sopenharmony_ci{
1120141cc406Sopenharmony_ci  struct P5_Session *session = (struct P5_Session *) handle;
1121141cc406Sopenharmony_ci  struct P5_Device *dev = session->dev;
1122141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
1123141cc406Sopenharmony_ci  int count;
1124141cc406Sopenharmony_ci  int size, lines;
1125141cc406Sopenharmony_ci  SANE_Bool x2;
1126141cc406Sopenharmony_ci  SANE_Int i;
1127141cc406Sopenharmony_ci
1128141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_read: start\n");
1129141cc406Sopenharmony_ci  DBG (DBG_io, "sane_read: up to %d bytes required by frontend\n", max_len);
1130141cc406Sopenharmony_ci
1131141cc406Sopenharmony_ci  /* some sanity checks first to protect from would be buggy frontends */
1132141cc406Sopenharmony_ci  if (!session)
1133141cc406Sopenharmony_ci    {
1134141cc406Sopenharmony_ci      DBG (DBG_error, "sane_read: handle is null!\n");
1135141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1136141cc406Sopenharmony_ci    }
1137141cc406Sopenharmony_ci
1138141cc406Sopenharmony_ci  if (!buf)
1139141cc406Sopenharmony_ci    {
1140141cc406Sopenharmony_ci      DBG (DBG_error, "sane_read: buf is null!\n");
1141141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1142141cc406Sopenharmony_ci    }
1143141cc406Sopenharmony_ci
1144141cc406Sopenharmony_ci  if (!len)
1145141cc406Sopenharmony_ci    {
1146141cc406Sopenharmony_ci      DBG (DBG_error, "sane_read: len is null!\n");
1147141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1148141cc406Sopenharmony_ci    }
1149141cc406Sopenharmony_ci
1150141cc406Sopenharmony_ci  /* no data read yet */
1151141cc406Sopenharmony_ci  *len = 0;
1152141cc406Sopenharmony_ci
1153141cc406Sopenharmony_ci  /* check if session is scanning */
1154141cc406Sopenharmony_ci  if (!session->scanning)
1155141cc406Sopenharmony_ci    {
1156141cc406Sopenharmony_ci      DBG (DBG_warn,
1157141cc406Sopenharmony_ci	   "sane_read: scan was cancelled, is over or has not been initiated yet\n");
1158141cc406Sopenharmony_ci      return SANE_STATUS_CANCELLED;
1159141cc406Sopenharmony_ci    }
1160141cc406Sopenharmony_ci
1161141cc406Sopenharmony_ci  /* check for EOF, must be done before any physical read */
1162141cc406Sopenharmony_ci  if (session->sent >= session->to_send)
1163141cc406Sopenharmony_ci    {
1164141cc406Sopenharmony_ci      DBG (DBG_io, "sane_read: end of scan reached\n");
1165141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
1166141cc406Sopenharmony_ci    }
1167141cc406Sopenharmony_ci
1168141cc406Sopenharmony_ci  /* if working buffer is empty, we do a physical data read */
1169141cc406Sopenharmony_ci  if (dev->top <= dev->bottom)
1170141cc406Sopenharmony_ci    {
1171141cc406Sopenharmony_ci      DBG (DBG_io, "sane_read: physical data read\n");
1172141cc406Sopenharmony_ci      /* check is there is data available. In case of non-blocking mode we return
1173141cc406Sopenharmony_ci       * as soon it is detected there is no data yet. Reads must by done line by
1174141cc406Sopenharmony_ci       * line, so we read only when count is bigger than bytes per line
1175141cc406Sopenharmony_ci       * */
1176141cc406Sopenharmony_ci      count = available_bytes (dev->fd);
1177141cc406Sopenharmony_ci      DBG (DBG_io, "sane_read: count=%d bytes\n", count);
1178141cc406Sopenharmony_ci      if (count < dev->bytes_per_line && session->non_blocking == SANE_TRUE)
1179141cc406Sopenharmony_ci	{
1180141cc406Sopenharmony_ci	  DBG (DBG_io, "sane_read: scanner hasn't enough data available\n");
1181141cc406Sopenharmony_ci	  DBG (DBG_proc, "sane_read: exit\n");
1182141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1183141cc406Sopenharmony_ci	}
1184141cc406Sopenharmony_ci
1185141cc406Sopenharmony_ci      /* now we can wait for data here */
1186141cc406Sopenharmony_ci      while (count < dev->bytes_per_line)
1187141cc406Sopenharmony_ci	{
1188141cc406Sopenharmony_ci	  /* test if document left the feeder, so we have to terminate the scan */
1189141cc406Sopenharmony_ci	  status = test_document (dev->fd);
1190141cc406Sopenharmony_ci	  if (status == SANE_STATUS_NO_DOCS)
1191141cc406Sopenharmony_ci	    {
1192141cc406Sopenharmony_ci	      session->to_send = session->sent;
1193141cc406Sopenharmony_ci	      return SANE_STATUS_EOF;
1194141cc406Sopenharmony_ci	    }
1195141cc406Sopenharmony_ci
1196141cc406Sopenharmony_ci	  /* don't call scanner too often */
1197141cc406Sopenharmony_ci	  usleep (10000);
1198141cc406Sopenharmony_ci	  count = available_bytes (dev->fd);
1199141cc406Sopenharmony_ci	}
1200141cc406Sopenharmony_ci
1201141cc406Sopenharmony_ci      /** compute size of physical data to read
1202141cc406Sopenharmony_ci       * on first read, position will be 0, while it will be 'bottom'
1203141cc406Sopenharmony_ci       * for the subsequent reads.
1204141cc406Sopenharmony_ci       * We try to read a complete buffer */
1205141cc406Sopenharmony_ci      size = dev->size - dev->position;
1206141cc406Sopenharmony_ci
1207141cc406Sopenharmony_ci      if (session->to_send - session->sent < size)
1208141cc406Sopenharmony_ci	{
1209141cc406Sopenharmony_ci	  /* not enough data left, so read remainder of scan */
1210141cc406Sopenharmony_ci	  size = session->to_send - session->sent;
1211141cc406Sopenharmony_ci	}
1212141cc406Sopenharmony_ci
1213141cc406Sopenharmony_ci      /* 600 dpi is 300x600 physical, and 400 is 200x400 */
1214141cc406Sopenharmony_ci      if (dev->ydpi > dev->model->max_xdpi)
1215141cc406Sopenharmony_ci	{
1216141cc406Sopenharmony_ci	  x2 = SANE_TRUE;
1217141cc406Sopenharmony_ci	}
1218141cc406Sopenharmony_ci      else
1219141cc406Sopenharmony_ci	{
1220141cc406Sopenharmony_ci	  x2 = SANE_FALSE;
1221141cc406Sopenharmony_ci	}
1222141cc406Sopenharmony_ci      lines = read_line (dev,
1223141cc406Sopenharmony_ci			 dev->buffer + dev->position,
1224141cc406Sopenharmony_ci			 dev->bytes_per_line,
1225141cc406Sopenharmony_ci			 size / dev->bytes_per_line,
1226141cc406Sopenharmony_ci			 SANE_TRUE, x2, dev->mode, dev->calibrated);
1227141cc406Sopenharmony_ci
1228141cc406Sopenharmony_ci      /* handle document end detection TODO try to recover the partial
1229141cc406Sopenharmony_ci       * buffer already read before EOD */
1230141cc406Sopenharmony_ci      if (lines == -1)
1231141cc406Sopenharmony_ci	{
1232141cc406Sopenharmony_ci	  DBG (DBG_io, "sane_read: error reading line\n");
1233141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
1234141cc406Sopenharmony_ci	}
1235141cc406Sopenharmony_ci
1236141cc406Sopenharmony_ci      /* gather lines until we have more than needed for lds */
1237141cc406Sopenharmony_ci      dev->position += lines * dev->bytes_per_line;
1238141cc406Sopenharmony_ci      dev->top = dev->position;
1239141cc406Sopenharmony_ci      if (dev->position > dev->bottom)
1240141cc406Sopenharmony_ci	{
1241141cc406Sopenharmony_ci	  dev->position = dev->bottom;
1242141cc406Sopenharmony_ci	}
1243141cc406Sopenharmony_ci      DBG (DBG_io, "sane_read: size    =%lu\n", (unsigned long)dev->size);
1244141cc406Sopenharmony_ci      DBG (DBG_io, "sane_read: bottom  =%lu\n", (unsigned long)dev->bottom);
1245141cc406Sopenharmony_ci      DBG (DBG_io, "sane_read: position=%lu\n", (unsigned long)dev->position);
1246141cc406Sopenharmony_ci      DBG (DBG_io, "sane_read: top     =%lu\n", (unsigned long)dev->top);
1247141cc406Sopenharmony_ci    }				/* end of physical data reading */
1248141cc406Sopenharmony_ci
1249141cc406Sopenharmony_ci  /* logical data reading */
1250141cc406Sopenharmony_ci  /* check if there data available in working buffer */
1251141cc406Sopenharmony_ci  if (dev->position < dev->top && dev->position >= dev->bottom)
1252141cc406Sopenharmony_ci    {
1253141cc406Sopenharmony_ci      DBG (DBG_io, "sane_read: logical data read\n");
1254141cc406Sopenharmony_ci      /* we have more data in internal buffer than asked ,
1255141cc406Sopenharmony_ci       * then send only max data */
1256141cc406Sopenharmony_ci      size = dev->top - dev->position;
1257141cc406Sopenharmony_ci      if (max_len < size)
1258141cc406Sopenharmony_ci	{
1259141cc406Sopenharmony_ci	  *len = max_len;
1260141cc406Sopenharmony_ci	}
1261141cc406Sopenharmony_ci      else
1262141cc406Sopenharmony_ci	/* if we don't have enough, send all what we have */
1263141cc406Sopenharmony_ci	{
1264141cc406Sopenharmony_ci	  *len = dev->top - dev->position;
1265141cc406Sopenharmony_ci	}
1266141cc406Sopenharmony_ci
1267141cc406Sopenharmony_ci      /* data copy */
1268141cc406Sopenharmony_ci      if (dev->lds == 0)
1269141cc406Sopenharmony_ci	{
1270141cc406Sopenharmony_ci	  memcpy (buf, dev->buffer + dev->position, *len);
1271141cc406Sopenharmony_ci	}
1272141cc406Sopenharmony_ci      else
1273141cc406Sopenharmony_ci	{
1274141cc406Sopenharmony_ci	  /* compute count of bytes for lds */
1275141cc406Sopenharmony_ci	  count = dev->lds * dev->bytes_per_line;
1276141cc406Sopenharmony_ci
1277141cc406Sopenharmony_ci	  /* adjust for lds as we copy data to frontend */
1278141cc406Sopenharmony_ci	  for (i = 0; i < *len; i++)
1279141cc406Sopenharmony_ci	    {
1280141cc406Sopenharmony_ci	      switch ((dev->position + i) % 3)
1281141cc406Sopenharmony_ci		{
1282141cc406Sopenharmony_ci		  /* red */
1283141cc406Sopenharmony_ci		case 0:
1284141cc406Sopenharmony_ci		  buf[i] = dev->buffer[dev->position + i - 2 * count];
1285141cc406Sopenharmony_ci		  break;
1286141cc406Sopenharmony_ci		  /* green */
1287141cc406Sopenharmony_ci		case 1:
1288141cc406Sopenharmony_ci		  buf[i] = dev->buffer[dev->position + i - count];
1289141cc406Sopenharmony_ci		  break;
1290141cc406Sopenharmony_ci		  /* blue */
1291141cc406Sopenharmony_ci		default:
1292141cc406Sopenharmony_ci		  buf[i] = dev->buffer[dev->position + i];
1293141cc406Sopenharmony_ci		  break;
1294141cc406Sopenharmony_ci		}
1295141cc406Sopenharmony_ci	    }
1296141cc406Sopenharmony_ci	}
1297141cc406Sopenharmony_ci      dev->position += *len;
1298141cc406Sopenharmony_ci
1299141cc406Sopenharmony_ci      /* update byte accounting */
1300141cc406Sopenharmony_ci      session->sent += *len;
1301141cc406Sopenharmony_ci      DBG (DBG_io, "sane_read: sent %d bytes from buffer to frontend\n",
1302141cc406Sopenharmony_ci	   *len);
1303141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
1304141cc406Sopenharmony_ci    }
1305141cc406Sopenharmony_ci
1306141cc406Sopenharmony_ci  /* check if we exhausted working buffer */
1307141cc406Sopenharmony_ci  if (dev->position >= dev->top && dev->position >= dev->bottom)
1308141cc406Sopenharmony_ci    {
1309141cc406Sopenharmony_ci      /* copy extra lines needed for lds in next buffer */
1310141cc406Sopenharmony_ci      if (dev->position > dev->bottom && dev->lds > 0)
1311141cc406Sopenharmony_ci	{
1312141cc406Sopenharmony_ci	  memcpy (dev->buffer,
1313141cc406Sopenharmony_ci		  dev->buffer + dev->position - dev->bottom, dev->bottom);
1314141cc406Sopenharmony_ci	}
1315141cc406Sopenharmony_ci
1316141cc406Sopenharmony_ci      /* restart buffer */
1317141cc406Sopenharmony_ci      dev->position = dev->bottom;
1318141cc406Sopenharmony_ci      dev->top = 0;
1319141cc406Sopenharmony_ci    }
1320141cc406Sopenharmony_ci
1321141cc406Sopenharmony_ci  DBG (DBG_io, "sane_read: size    =%lu\n", (unsigned long)dev->size);
1322141cc406Sopenharmony_ci  DBG (DBG_io, "sane_read: bottom  =%lu\n", (unsigned long)dev->bottom);
1323141cc406Sopenharmony_ci  DBG (DBG_io, "sane_read: position=%lu\n", (unsigned long)dev->position);
1324141cc406Sopenharmony_ci  DBG (DBG_io, "sane_read: top     =%lu\n", (unsigned long)dev->top);
1325141cc406Sopenharmony_ci
1326141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_read: exit\n");
1327141cc406Sopenharmony_ci  return status;
1328141cc406Sopenharmony_ci}
1329141cc406Sopenharmony_ci
1330141cc406Sopenharmony_ci
1331141cc406Sopenharmony_ci/**
1332141cc406Sopenharmony_ci * Cancels a scan.
1333141cc406Sopenharmony_ci *
1334141cc406Sopenharmony_ci * From the SANE spec:
1335141cc406Sopenharmony_ci * This function is used to immediately or as quickly as possible
1336141cc406Sopenharmony_ci * cancel the currently pending operation of the device represented by
1337141cc406Sopenharmony_ci * handle h.  This function can be called at any time (as long as
1338141cc406Sopenharmony_ci * handle h is a valid handle) but usually affects long-running
1339141cc406Sopenharmony_ci * operations only (such as image is acquisition). It is safe to call
1340141cc406Sopenharmony_ci * this function asynchronously (e.g., from within a signal handler).
1341141cc406Sopenharmony_ci * It is important to note that completion of this operation does not
1342141cc406Sopenharmony_ci * imply that the currently pending operation has been cancelled. It
1343141cc406Sopenharmony_ci * only guarantees that cancellation has been initiated. Cancellation
1344141cc406Sopenharmony_ci * completes only when the cancelled call returns (typically with a
1345141cc406Sopenharmony_ci * status value of SANE_STATUS_CANCELLED).  Since the SANE API does
1346141cc406Sopenharmony_ci * not require any other operations to be re-entrant, this implies
1347141cc406Sopenharmony_ci * that a frontend must not call any other operation until the
1348141cc406Sopenharmony_ci * cancelled operation has returned.
1349141cc406Sopenharmony_ci */
1350141cc406Sopenharmony_civoid
1351141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
1352141cc406Sopenharmony_ci{
1353141cc406Sopenharmony_ci  P5_Session *session = handle;
1354141cc406Sopenharmony_ci
1355141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_cancel: start\n");
1356141cc406Sopenharmony_ci
1357141cc406Sopenharmony_ci  /* if scanning, abort and park head */
1358141cc406Sopenharmony_ci  if (session->scanning == SANE_TRUE)
1359141cc406Sopenharmony_ci    {
1360141cc406Sopenharmony_ci      /* detects if we are called after the scan is finished,
1361141cc406Sopenharmony_ci       * or if the scan is aborted */
1362141cc406Sopenharmony_ci      if (session->sent < session->to_send)
1363141cc406Sopenharmony_ci	{
1364141cc406Sopenharmony_ci	  DBG (DBG_info, "sane_cancel: aborting scan.\n");
1365141cc406Sopenharmony_ci	  /* device hasn't finished scan, we are aborting it
1366141cc406Sopenharmony_ci	   * and we may have to do something specific for it here */
1367141cc406Sopenharmony_ci	}
1368141cc406Sopenharmony_ci      else
1369141cc406Sopenharmony_ci	{
1370141cc406Sopenharmony_ci	  DBG (DBG_info, "sane_cancel: cleaning up after scan.\n");
1371141cc406Sopenharmony_ci	}
1372141cc406Sopenharmony_ci      session->scanning = SANE_FALSE;
1373141cc406Sopenharmony_ci    }
1374141cc406Sopenharmony_ci  eject (session->dev->fd);
1375141cc406Sopenharmony_ci
1376141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_cancel: exit\n");
1377141cc406Sopenharmony_ci}
1378141cc406Sopenharmony_ci
1379141cc406Sopenharmony_ci
1380141cc406Sopenharmony_ci/**
1381141cc406Sopenharmony_ci * Ends use of the session.
1382141cc406Sopenharmony_ci *
1383141cc406Sopenharmony_ci * From the SANE spec:
1384141cc406Sopenharmony_ci * This function terminates the association between the device handle
1385141cc406Sopenharmony_ci * passed in argument h and the device it represents. If the device is
1386141cc406Sopenharmony_ci * presently active, a call to sane_cancel() is performed first. After
1387141cc406Sopenharmony_ci * this function returns, handle h must not be used anymore.
1388141cc406Sopenharmony_ci *
1389141cc406Sopenharmony_ci * Handle resources are free'd before disposing the handle. But devices
1390141cc406Sopenharmony_ci * resources must not be mdofied, since it could be used or reused until
1391141cc406Sopenharmony_ci * sane_exit() is called.
1392141cc406Sopenharmony_ci */
1393141cc406Sopenharmony_civoid
1394141cc406Sopenharmony_cisane_close (SANE_Handle handle)
1395141cc406Sopenharmony_ci{
1396141cc406Sopenharmony_ci  P5_Session *prev, *session;
1397141cc406Sopenharmony_ci
1398141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_close: start\n");
1399141cc406Sopenharmony_ci
1400141cc406Sopenharmony_ci  /* remove handle from list of open handles: */
1401141cc406Sopenharmony_ci  prev = NULL;
1402141cc406Sopenharmony_ci  for (session = sessions; session; session = session->next)
1403141cc406Sopenharmony_ci    {
1404141cc406Sopenharmony_ci      if (session == handle)
1405141cc406Sopenharmony_ci	break;
1406141cc406Sopenharmony_ci      prev = session;
1407141cc406Sopenharmony_ci    }
1408141cc406Sopenharmony_ci  if (!session)
1409141cc406Sopenharmony_ci    {
1410141cc406Sopenharmony_ci      DBG (DBG_error0, "close: invalid handle %p\n", handle);
1411141cc406Sopenharmony_ci      return;			/* oops, not a handle we know about */
1412141cc406Sopenharmony_ci    }
1413141cc406Sopenharmony_ci
1414141cc406Sopenharmony_ci  /* cancel any active scan */
1415141cc406Sopenharmony_ci  if (session->scanning == SANE_TRUE)
1416141cc406Sopenharmony_ci    {
1417141cc406Sopenharmony_ci      sane_cancel (handle);
1418141cc406Sopenharmony_ci    }
1419141cc406Sopenharmony_ci
1420141cc406Sopenharmony_ci  if (prev)
1421141cc406Sopenharmony_ci    prev->next = session->next;
1422141cc406Sopenharmony_ci  else
1423141cc406Sopenharmony_ci    sessions = session->next;
1424141cc406Sopenharmony_ci
1425141cc406Sopenharmony_ci  /* close low level device */
1426141cc406Sopenharmony_ci  if (session->dev->initialized == SANE_TRUE)
1427141cc406Sopenharmony_ci    {
1428141cc406Sopenharmony_ci      if (session->dev->calibrated == SANE_TRUE)
1429141cc406Sopenharmony_ci	{
1430141cc406Sopenharmony_ci	  save_calibration (session->dev);
1431141cc406Sopenharmony_ci	}
1432141cc406Sopenharmony_ci      disconnect (session->dev->fd);
1433141cc406Sopenharmony_ci      close_pp (session->dev->fd);
1434141cc406Sopenharmony_ci      session->dev->fd = -1;
1435141cc406Sopenharmony_ci      session->dev->initialized = SANE_FALSE;
1436141cc406Sopenharmony_ci
1437141cc406Sopenharmony_ci      /* free device data */
1438141cc406Sopenharmony_ci      if (session->dev->buffer != NULL)
1439141cc406Sopenharmony_ci	{
1440141cc406Sopenharmony_ci	  free (session->dev->buffer);
1441141cc406Sopenharmony_ci	}
1442141cc406Sopenharmony_ci      if (session->dev->buffer != NULL)
1443141cc406Sopenharmony_ci	{
1444141cc406Sopenharmony_ci	  free (session->dev->gain);
1445141cc406Sopenharmony_ci	  free (session->dev->offset);
1446141cc406Sopenharmony_ci	}
1447141cc406Sopenharmony_ci      if (session->dev->calibrated == SANE_TRUE)
1448141cc406Sopenharmony_ci	{
1449141cc406Sopenharmony_ci	  cleanup_calibration (session->dev);
1450141cc406Sopenharmony_ci	}
1451141cc406Sopenharmony_ci    }
1452141cc406Sopenharmony_ci
1453141cc406Sopenharmony_ci  /* free per session data */
1454141cc406Sopenharmony_ci  free (session->options[OPT_MODE].value.s);
1455141cc406Sopenharmony_ci  free ((void *)session->options[OPT_RESOLUTION].descriptor.constraint.word_list);
1456141cc406Sopenharmony_ci
1457141cc406Sopenharmony_ci  free (session);
1458141cc406Sopenharmony_ci
1459141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_close: exit\n");
1460141cc406Sopenharmony_ci}
1461141cc406Sopenharmony_ci
1462141cc406Sopenharmony_ci
1463141cc406Sopenharmony_ci/**
1464141cc406Sopenharmony_ci * Terminates the backend.
1465141cc406Sopenharmony_ci *
1466141cc406Sopenharmony_ci * From the SANE spec:
1467141cc406Sopenharmony_ci * This function must be called to terminate use of a backend. The
1468141cc406Sopenharmony_ci * function will first close all device handles that still might be
1469141cc406Sopenharmony_ci * open (it is recommended to close device handles explicitly through
1470141cc406Sopenharmony_ci * a call to sane_close(), but backends are required to release all
1471141cc406Sopenharmony_ci * resources upon a call to this function). After this function
1472141cc406Sopenharmony_ci * returns, no function other than sane_init() may be called
1473141cc406Sopenharmony_ci * (regardless of the status value returned by sane_exit(). Neglecting
1474141cc406Sopenharmony_ci * to call this function may result in some resources not being
1475141cc406Sopenharmony_ci * released properly.
1476141cc406Sopenharmony_ci */
1477141cc406Sopenharmony_civoid
1478141cc406Sopenharmony_cisane_exit (void)
1479141cc406Sopenharmony_ci{
1480141cc406Sopenharmony_ci  struct P5_Session *session, *next;
1481141cc406Sopenharmony_ci  struct P5_Device *dev, *nextdev;
1482141cc406Sopenharmony_ci  int i;
1483141cc406Sopenharmony_ci
1484141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_exit: start\n");
1485141cc406Sopenharmony_ci  init_count--;
1486141cc406Sopenharmony_ci
1487141cc406Sopenharmony_ci  if (init_count > 0)
1488141cc406Sopenharmony_ci    {
1489141cc406Sopenharmony_ci      DBG (DBG_info,
1490141cc406Sopenharmony_ci	   "sane_exit: still %d fronteds to leave before effective exit.\n",
1491141cc406Sopenharmony_ci	   init_count);
1492141cc406Sopenharmony_ci      return;
1493141cc406Sopenharmony_ci    }
1494141cc406Sopenharmony_ci
1495141cc406Sopenharmony_ci  /* free session structs */
1496141cc406Sopenharmony_ci  for (session = sessions; session; session = next)
1497141cc406Sopenharmony_ci    {
1498141cc406Sopenharmony_ci      next = session->next;
1499141cc406Sopenharmony_ci      sane_close ((SANE_Handle *) session);
1500141cc406Sopenharmony_ci      free (session);
1501141cc406Sopenharmony_ci    }
1502141cc406Sopenharmony_ci  sessions = NULL;
1503141cc406Sopenharmony_ci
1504141cc406Sopenharmony_ci  /* free devices structs */
1505141cc406Sopenharmony_ci  for (dev = devices; dev; dev = nextdev)
1506141cc406Sopenharmony_ci    {
1507141cc406Sopenharmony_ci      nextdev = dev->next;
1508141cc406Sopenharmony_ci      free (dev->name);
1509141cc406Sopenharmony_ci      free (dev);
1510141cc406Sopenharmony_ci    }
1511141cc406Sopenharmony_ci  devices = NULL;
1512141cc406Sopenharmony_ci
1513141cc406Sopenharmony_ci  /* now list of devices */
1514141cc406Sopenharmony_ci  if (devlist)
1515141cc406Sopenharmony_ci    {
1516141cc406Sopenharmony_ci      i = 0;
1517141cc406Sopenharmony_ci      while ((SANE_Device *) devlist[i])
1518141cc406Sopenharmony_ci	{
1519141cc406Sopenharmony_ci	  free ((SANE_Device *) devlist[i]);
1520141cc406Sopenharmony_ci	  i++;
1521141cc406Sopenharmony_ci	}
1522141cc406Sopenharmony_ci      free (devlist);
1523141cc406Sopenharmony_ci      devlist = NULL;
1524141cc406Sopenharmony_ci    }
1525141cc406Sopenharmony_ci
1526141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_exit: exit\n");
1527141cc406Sopenharmony_ci}
1528141cc406Sopenharmony_ci
1529141cc406Sopenharmony_ci
1530141cc406Sopenharmony_ci/** @brief probe for all supported devices
1531141cc406Sopenharmony_ci * This functions tries to probe if any of the supported devices of
1532141cc406Sopenharmony_ci * the backend is present. Each detected device will be added to the
1533141cc406Sopenharmony_ci * 'devices' list
1534141cc406Sopenharmony_ci */
1535141cc406Sopenharmony_cistatic SANE_Status
1536141cc406Sopenharmony_ciprobe_p5_devices (void)
1537141cc406Sopenharmony_ci{
1538141cc406Sopenharmony_ci  /**> configuration structure used during attach */
1539141cc406Sopenharmony_ci  SANEI_Config config;
1540141cc406Sopenharmony_ci  /**> list of configuration options */
1541141cc406Sopenharmony_ci  SANE_Option_Descriptor *cfg_options[NUM_CFG_OPTIONS];
1542141cc406Sopenharmony_ci  /**> placeholders pointers for option values */
1543141cc406Sopenharmony_ci  void *values[NUM_CFG_OPTIONS];
1544141cc406Sopenharmony_ci  int i;
1545141cc406Sopenharmony_ci  SANE_Status status;
1546141cc406Sopenharmony_ci
1547141cc406Sopenharmony_ci  DBG (DBG_proc, "probe_p5_devices: start\n");
1548141cc406Sopenharmony_ci
1549141cc406Sopenharmony_ci  /* initialize configuration options */
1550141cc406Sopenharmony_ci  cfg_options[CFG_MODEL_NAME] =
1551141cc406Sopenharmony_ci    (SANE_Option_Descriptor *) malloc (sizeof (SANE_Option_Descriptor));
1552141cc406Sopenharmony_ci  cfg_options[CFG_MODEL_NAME]->name = "modelname";
1553141cc406Sopenharmony_ci  cfg_options[CFG_MODEL_NAME]->desc = "user provided scanner's model name";
1554141cc406Sopenharmony_ci  cfg_options[CFG_MODEL_NAME]->type = SANE_TYPE_INT;
1555141cc406Sopenharmony_ci  cfg_options[CFG_MODEL_NAME]->unit = SANE_UNIT_NONE;
1556141cc406Sopenharmony_ci  cfg_options[CFG_MODEL_NAME]->size = sizeof (SANE_Word);
1557141cc406Sopenharmony_ci  cfg_options[CFG_MODEL_NAME]->cap = SANE_CAP_SOFT_SELECT;
1558141cc406Sopenharmony_ci  cfg_options[CFG_MODEL_NAME]->constraint_type = SANE_CONSTRAINT_NONE;
1559141cc406Sopenharmony_ci  values[CFG_MODEL_NAME] = &p5cfg.modelname;
1560141cc406Sopenharmony_ci
1561141cc406Sopenharmony_ci  /* set configuration options structure */
1562141cc406Sopenharmony_ci  config.descriptors = cfg_options;
1563141cc406Sopenharmony_ci  config.values = values;
1564141cc406Sopenharmony_ci  config.count = NUM_CFG_OPTIONS;
1565141cc406Sopenharmony_ci
1566141cc406Sopenharmony_ci  /* generic configure and attach function */
1567141cc406Sopenharmony_ci  status = sanei_configure_attach (P5_CONFIG_FILE, &config,
1568141cc406Sopenharmony_ci                                   config_attach, NULL);
1569141cc406Sopenharmony_ci  /* free allocated options */
1570141cc406Sopenharmony_ci  for (i = 0; i < NUM_CFG_OPTIONS; i++)
1571141cc406Sopenharmony_ci    {
1572141cc406Sopenharmony_ci      free (cfg_options[i]);
1573141cc406Sopenharmony_ci    }
1574141cc406Sopenharmony_ci
1575141cc406Sopenharmony_ci  DBG (DBG_proc, "probe_p5_devices: end\n");
1576141cc406Sopenharmony_ci  return status;
1577141cc406Sopenharmony_ci}
1578141cc406Sopenharmony_ci
1579141cc406Sopenharmony_ci/** This function is called by sanei_configure_attach to try
1580141cc406Sopenharmony_ci * to attach the backend to a device specified by the configuration file.
1581141cc406Sopenharmony_ci *
1582141cc406Sopenharmony_ci * @param config configuration structure filled with values read
1583141cc406Sopenharmony_ci * 	         from configuration file
1584141cc406Sopenharmony_ci * @param devname name of the device to try to attach to, it is
1585141cc406Sopenharmony_ci * 	          the unprocessed line of the configuration file
1586141cc406Sopenharmony_ci *
1587141cc406Sopenharmony_ci * @return status SANE_STATUS_GOOD if no errors (even if no matching
1588141cc406Sopenharmony_ci * 	    devices found)
1589141cc406Sopenharmony_ci * 	   SANE_STATUS_INVAL in case of error
1590141cc406Sopenharmony_ci */
1591141cc406Sopenharmony_cistatic SANE_Status
1592141cc406Sopenharmony_ciconfig_attach (SANEI_Config __sane_unused__ * config, const char *devname,
1593141cc406Sopenharmony_ci               void __sane_unused__ *data)
1594141cc406Sopenharmony_ci{
1595141cc406Sopenharmony_ci  /* currently, the config is a global variable so config is useless here */
1596141cc406Sopenharmony_ci  /* the correct thing would be to have a generic sanei_attach_matching_devices
1597141cc406Sopenharmony_ci   * using an attach function with a config parameter */
1598141cc406Sopenharmony_ci  (void) config;
1599141cc406Sopenharmony_ci
1600141cc406Sopenharmony_ci  /* the devname has been processed and is ready to be used
1601141cc406Sopenharmony_ci   * directly. The config struct contains all the configuration data for
1602141cc406Sopenharmony_ci   * the corresponding device. Since there is no resources common to each
1603141cc406Sopenharmony_ci   * backends regarding parallel port, we can directly call the attach
1604141cc406Sopenharmony_ci   * function. */
1605141cc406Sopenharmony_ci  attach_p5 (devname, config);
1606141cc406Sopenharmony_ci
1607141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1608141cc406Sopenharmony_ci}
1609141cc406Sopenharmony_ci
1610141cc406Sopenharmony_ci/** @brief try to attach to a device by its name
1611141cc406Sopenharmony_ci * The attach tries to open the given device and match it
1612141cc406Sopenharmony_ci * with devices handled by the backend. The configuration parameter
1613141cc406Sopenharmony_ci * contains the values of the already parsed configuration options
1614141cc406Sopenharmony_ci * from the conf file.
1615141cc406Sopenharmony_ci * @param config configuration structure filled with values read
1616141cc406Sopenharmony_ci * 	         from configuration file
1617141cc406Sopenharmony_ci * @param devicename name of the device to try to attach to, it is
1618141cc406Sopenharmony_ci * 	          the unprocessed line of the configuration file
1619141cc406Sopenharmony_ci *
1620141cc406Sopenharmony_ci * @return status SANE_STATUS_GOOD if no errors (even if no matching
1621141cc406Sopenharmony_ci * 	    devices found)
1622141cc406Sopenharmony_ci * 	   SANE_STATUS_NOM_MEM if there isn't enough memory to allocate the
1623141cc406Sopenharmony_ci * 	   			device structure
1624141cc406Sopenharmony_ci * 	   SANE_STATUS_UNSUPPORTED if the device if unknown by the backend
1625141cc406Sopenharmony_ci * 	   SANE_STATUS_INVAL in case of other error
1626141cc406Sopenharmony_ci */
1627141cc406Sopenharmony_cistatic SANE_Status
1628141cc406Sopenharmony_ciattach_p5 (const char *devicename, SANEI_Config * config)
1629141cc406Sopenharmony_ci{
1630141cc406Sopenharmony_ci  struct P5_Device *device;
1631141cc406Sopenharmony_ci  struct P5_Model *model;
1632141cc406Sopenharmony_ci
1633141cc406Sopenharmony_ci  DBG (DBG_proc, "attach(%s): start\n", devicename);
1634141cc406Sopenharmony_ci  if(config==NULL)
1635141cc406Sopenharmony_ci    {
1636141cc406Sopenharmony_ci      DBG (DBG_warn, "attach: config is NULL\n");
1637141cc406Sopenharmony_ci    }
1638141cc406Sopenharmony_ci
1639141cc406Sopenharmony_ci  /* search if we already have it attached */
1640141cc406Sopenharmony_ci  for (device = devices; device; device = device->next)
1641141cc406Sopenharmony_ci    {
1642141cc406Sopenharmony_ci      if (strcmp (device->name, devicename) == 0)
1643141cc406Sopenharmony_ci	{
1644141cc406Sopenharmony_ci	  DBG (DBG_info, "attach: device already attached\n");
1645141cc406Sopenharmony_ci	  DBG (DBG_proc, "attach: exit\n");
1646141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1647141cc406Sopenharmony_ci	}
1648141cc406Sopenharmony_ci    }
1649141cc406Sopenharmony_ci
1650141cc406Sopenharmony_ci  /**
1651141cc406Sopenharmony_ci   * do physical probe of the device here. In case the device is recognized,
1652141cc406Sopenharmony_ci   * we allocate a device struct and give it options and model.
1653141cc406Sopenharmony_ci   * Else we return SANE_STATUS_UNSUPPORTED.
1654141cc406Sopenharmony_ci   */
1655141cc406Sopenharmony_ci  model = probe (devicename);
1656141cc406Sopenharmony_ci  if (model == NULL)
1657141cc406Sopenharmony_ci    {
1658141cc406Sopenharmony_ci      DBG (DBG_info,
1659141cc406Sopenharmony_ci	   "attach: device %s is not managed by the backend\n", devicename);
1660141cc406Sopenharmony_ci      DBG (DBG_proc, "attach: exit\n");
1661141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
1662141cc406Sopenharmony_ci    }
1663141cc406Sopenharmony_ci
1664141cc406Sopenharmony_ci  /* allocate device struct */
1665141cc406Sopenharmony_ci  device = malloc (sizeof (*device));
1666141cc406Sopenharmony_ci  if (device == NULL)
1667141cc406Sopenharmony_ci    {
1668141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1669141cc406Sopenharmony_ci      DBG (DBG_proc, "attach: exit\n");
1670141cc406Sopenharmony_ci    }
1671141cc406Sopenharmony_ci  memset (device, 0, sizeof (*device));
1672141cc406Sopenharmony_ci  device->model = model;
1673141cc406Sopenharmony_ci
1674141cc406Sopenharmony_ci  /* name of the device */
1675141cc406Sopenharmony_ci  device->name = strdup (devicename);
1676141cc406Sopenharmony_ci
1677141cc406Sopenharmony_ci  DBG (DBG_info, "attach: found %s %s %s at %s\n",
1678141cc406Sopenharmony_ci       device->model->vendor, device->model->product, device->model->type,
1679141cc406Sopenharmony_ci       device->name);
1680141cc406Sopenharmony_ci
1681141cc406Sopenharmony_ci  /* we insert new device at start of the chained list */
1682141cc406Sopenharmony_ci  /* head of the list becomes the next, and start is replaced */
1683141cc406Sopenharmony_ci  /* with the new session struct */
1684141cc406Sopenharmony_ci  device->next = devices;
1685141cc406Sopenharmony_ci  devices = device;
1686141cc406Sopenharmony_ci
1687141cc406Sopenharmony_ci  /* initialization is done at sane_open */
1688141cc406Sopenharmony_ci  device->initialized = SANE_FALSE;
1689141cc406Sopenharmony_ci  device->calibrated = SANE_FALSE;
1690141cc406Sopenharmony_ci
1691141cc406Sopenharmony_ci  DBG (DBG_proc, "attach: exit\n");
1692141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1693141cc406Sopenharmony_ci}
1694141cc406Sopenharmony_ci
1695141cc406Sopenharmony_ci
1696141cc406Sopenharmony_ci/** @brief set initial value for the scanning options
1697141cc406Sopenharmony_ci * for each sessions, control options are initialized based on the capability
1698141cc406Sopenharmony_ci * of the model of the physical device.
1699141cc406Sopenharmony_ci * @param session scanner session to initialize options
1700141cc406Sopenharmony_ci * @return SANE_STATUS_GOOD on success
1701141cc406Sopenharmony_ci */
1702141cc406Sopenharmony_cistatic SANE_Status
1703141cc406Sopenharmony_ciinit_options (struct P5_Session *session)
1704141cc406Sopenharmony_ci{
1705141cc406Sopenharmony_ci  SANE_Int option, i, min, idx;
1706141cc406Sopenharmony_ci  SANE_Word *dpi_list;
1707141cc406Sopenharmony_ci  P5_Model *model = session->dev->model;
1708141cc406Sopenharmony_ci
1709141cc406Sopenharmony_ci  DBG (DBG_proc, "init_options: start\n");
1710141cc406Sopenharmony_ci
1711141cc406Sopenharmony_ci  /* we first initialize each options with a default value */
1712141cc406Sopenharmony_ci  memset (session->options, 0, sizeof (session->options[OPT_NUM_OPTS]));
1713141cc406Sopenharmony_ci  for (option = 0; option < NUM_OPTIONS; option++)
1714141cc406Sopenharmony_ci    {
1715141cc406Sopenharmony_ci      session->options[option].descriptor.size = sizeof (SANE_Word);
1716141cc406Sopenharmony_ci      session->options[option].descriptor.cap =
1717141cc406Sopenharmony_ci	SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1718141cc406Sopenharmony_ci    }
1719141cc406Sopenharmony_ci
1720141cc406Sopenharmony_ci  /* we set up all the options listed in the P5_Option enum */
1721141cc406Sopenharmony_ci
1722141cc406Sopenharmony_ci  /* last option / end of list marker */
1723141cc406Sopenharmony_ci  session->options[OPT_NUM_OPTS].descriptor.name = SANE_NAME_NUM_OPTIONS;
1724141cc406Sopenharmony_ci  session->options[OPT_NUM_OPTS].descriptor.title = SANE_TITLE_NUM_OPTIONS;
1725141cc406Sopenharmony_ci  session->options[OPT_NUM_OPTS].descriptor.desc = SANE_DESC_NUM_OPTIONS;
1726141cc406Sopenharmony_ci  session->options[OPT_NUM_OPTS].descriptor.type = SANE_TYPE_INT;
1727141cc406Sopenharmony_ci  session->options[OPT_NUM_OPTS].descriptor.cap = SANE_CAP_SOFT_DETECT;
1728141cc406Sopenharmony_ci  session->options[OPT_NUM_OPTS].value.w = NUM_OPTIONS;
1729141cc406Sopenharmony_ci
1730141cc406Sopenharmony_ci  /* "Standard" group: */
1731141cc406Sopenharmony_ci  session->options[OPT_STANDARD_GROUP].descriptor.title = SANE_TITLE_STANDARD;
1732141cc406Sopenharmony_ci  session->options[OPT_STANDARD_GROUP].descriptor.name = SANE_NAME_STANDARD;
1733141cc406Sopenharmony_ci  session->options[OPT_STANDARD_GROUP].descriptor.desc = SANE_DESC_STANDARD;
1734141cc406Sopenharmony_ci  session->options[OPT_STANDARD_GROUP].descriptor.type = SANE_TYPE_GROUP;
1735141cc406Sopenharmony_ci  session->options[OPT_STANDARD_GROUP].descriptor.size = 0;
1736141cc406Sopenharmony_ci  session->options[OPT_STANDARD_GROUP].descriptor.cap = 0;
1737141cc406Sopenharmony_ci  session->options[OPT_STANDARD_GROUP].descriptor.constraint_type =
1738141cc406Sopenharmony_ci    SANE_CONSTRAINT_NONE;
1739141cc406Sopenharmony_ci
1740141cc406Sopenharmony_ci  /* scan mode */
1741141cc406Sopenharmony_ci  session->options[OPT_MODE].descriptor.name = SANE_NAME_SCAN_MODE;
1742141cc406Sopenharmony_ci  session->options[OPT_MODE].descriptor.title = SANE_TITLE_SCAN_MODE;
1743141cc406Sopenharmony_ci  session->options[OPT_MODE].descriptor.desc = SANE_DESC_SCAN_MODE;
1744141cc406Sopenharmony_ci  session->options[OPT_MODE].descriptor.type = SANE_TYPE_STRING;
1745141cc406Sopenharmony_ci  session->options[OPT_MODE].descriptor.cap |= SANE_CAP_AUTOMATIC;
1746141cc406Sopenharmony_ci  session->options[OPT_MODE].descriptor.constraint_type =
1747141cc406Sopenharmony_ci    SANE_CONSTRAINT_STRING_LIST;
1748141cc406Sopenharmony_ci  session->options[OPT_MODE].descriptor.size = max_string_size (mode_list);
1749141cc406Sopenharmony_ci  session->options[OPT_MODE].descriptor.constraint.string_list = mode_list;
1750141cc406Sopenharmony_ci  session->options[OPT_MODE].value.s = strdup (mode_list[0]);
1751141cc406Sopenharmony_ci
1752141cc406Sopenharmony_ci  /* preview */
1753141cc406Sopenharmony_ci  session->options[OPT_PREVIEW].descriptor.name = SANE_NAME_PREVIEW;
1754141cc406Sopenharmony_ci  session->options[OPT_PREVIEW].descriptor.title = SANE_TITLE_PREVIEW;
1755141cc406Sopenharmony_ci  session->options[OPT_PREVIEW].descriptor.desc = SANE_DESC_PREVIEW;
1756141cc406Sopenharmony_ci  session->options[OPT_PREVIEW].descriptor.type = SANE_TYPE_BOOL;
1757141cc406Sopenharmony_ci  session->options[OPT_PREVIEW].descriptor.cap |= SANE_CAP_AUTOMATIC;
1758141cc406Sopenharmony_ci  session->options[OPT_PREVIEW].descriptor.unit = SANE_UNIT_NONE;
1759141cc406Sopenharmony_ci  session->options[OPT_PREVIEW].descriptor.constraint_type =
1760141cc406Sopenharmony_ci    SANE_CONSTRAINT_NONE;
1761141cc406Sopenharmony_ci  session->options[OPT_PREVIEW].value.w = SANE_FALSE;
1762141cc406Sopenharmony_ci
1763141cc406Sopenharmony_ci  /** @brief build resolution list
1764141cc406Sopenharmony_ci   * We merge xdpi and ydpi list to provide only one resolution option control.
1765141cc406Sopenharmony_ci   * This is the most common case for backends and fronteds and give 'square'
1766141cc406Sopenharmony_ci   * pixels. The SANE API allow to control x and y dpi independently, but this is
1767141cc406Sopenharmony_ci   * rarely done and may confuse both frontends and users. In case a dpi value exists
1768141cc406Sopenharmony_ci   * for one but not for the other, the backend will have to crop data so that the
1769141cc406Sopenharmony_ci   * frontend is unaffected. A common case is that motor resolution (ydpi) is higher
1770141cc406Sopenharmony_ci   * than sensor resolution (xdpi), so scan lines must be scaled up to keep square
1771141cc406Sopenharmony_ci   * pixel when doing sane_read().
1772141cc406Sopenharmony_ci   * TODO this deserves a dedicated function and some unit testing
1773141cc406Sopenharmony_ci   */
1774141cc406Sopenharmony_ci
1775141cc406Sopenharmony_ci  /* find minimum first */
1776141cc406Sopenharmony_ci  min = 65535;
1777141cc406Sopenharmony_ci  for (i = 0; i < MAX_RESOLUTIONS && model->xdpi_values[i] > 0; i++)
1778141cc406Sopenharmony_ci    {
1779141cc406Sopenharmony_ci      if (model->xdpi_values[i] < min)
1780141cc406Sopenharmony_ci	min = model->xdpi_values[i];
1781141cc406Sopenharmony_ci    }
1782141cc406Sopenharmony_ci  for (i = 0; i < MAX_RESOLUTIONS && model->ydpi_values[i] > 0; i++)
1783141cc406Sopenharmony_ci    {
1784141cc406Sopenharmony_ci      if (model->ydpi_values[i] < min)
1785141cc406Sopenharmony_ci	min = model->ydpi_values[i];
1786141cc406Sopenharmony_ci    }
1787141cc406Sopenharmony_ci
1788141cc406Sopenharmony_ci  dpi_list = malloc ((MAX_RESOLUTIONS * 2 + 1) * sizeof (SANE_Word));
1789141cc406Sopenharmony_ci  if (!dpi_list)
1790141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1791141cc406Sopenharmony_ci  dpi_list[1] = min;
1792141cc406Sopenharmony_ci  idx = 2;
1793141cc406Sopenharmony_ci
1794141cc406Sopenharmony_ci  /* find any value greater than the last used min and
1795141cc406Sopenharmony_ci   * less than the max value
1796141cc406Sopenharmony_ci   */
1797141cc406Sopenharmony_ci  do
1798141cc406Sopenharmony_ci    {
1799141cc406Sopenharmony_ci      min = 65535;
1800141cc406Sopenharmony_ci      for (i = 0; i < MAX_RESOLUTIONS && model->xdpi_values[i] > 0; i++)
1801141cc406Sopenharmony_ci	{
1802141cc406Sopenharmony_ci	  if (model->xdpi_values[i] < min
1803141cc406Sopenharmony_ci	      && model->xdpi_values[i] > dpi_list[idx - 1])
1804141cc406Sopenharmony_ci	    min = model->xdpi_values[i];
1805141cc406Sopenharmony_ci	}
1806141cc406Sopenharmony_ci      for (i = 0; i < MAX_RESOLUTIONS && model->ydpi_values[i] > 0; i++)
1807141cc406Sopenharmony_ci	{
1808141cc406Sopenharmony_ci	  if (model->ydpi_values[i] < min
1809141cc406Sopenharmony_ci	      && model->ydpi_values[i] > dpi_list[idx - 1])
1810141cc406Sopenharmony_ci	    min = model->ydpi_values[i];
1811141cc406Sopenharmony_ci	}
1812141cc406Sopenharmony_ci      if (min < 65535)
1813141cc406Sopenharmony_ci	{
1814141cc406Sopenharmony_ci	  dpi_list[idx] = min;
1815141cc406Sopenharmony_ci	  idx++;
1816141cc406Sopenharmony_ci	}
1817141cc406Sopenharmony_ci    }
1818141cc406Sopenharmony_ci  while (min != 65535);
1819141cc406Sopenharmony_ci  dpi_list[idx] = 0;
1820141cc406Sopenharmony_ci  /* the count of different resolution is put at the beginning */
1821141cc406Sopenharmony_ci  dpi_list[0] = idx - 1;
1822141cc406Sopenharmony_ci
1823141cc406Sopenharmony_ci  session->options[OPT_RESOLUTION].descriptor.name =
1824141cc406Sopenharmony_ci    SANE_NAME_SCAN_RESOLUTION;
1825141cc406Sopenharmony_ci  session->options[OPT_RESOLUTION].descriptor.title =
1826141cc406Sopenharmony_ci    SANE_TITLE_SCAN_RESOLUTION;
1827141cc406Sopenharmony_ci  session->options[OPT_RESOLUTION].descriptor.desc =
1828141cc406Sopenharmony_ci    SANE_DESC_SCAN_RESOLUTION;
1829141cc406Sopenharmony_ci  session->options[OPT_RESOLUTION].descriptor.type = SANE_TYPE_INT;
1830141cc406Sopenharmony_ci  session->options[OPT_RESOLUTION].descriptor.cap |= SANE_CAP_AUTOMATIC;
1831141cc406Sopenharmony_ci  session->options[OPT_RESOLUTION].descriptor.unit = SANE_UNIT_DPI;
1832141cc406Sopenharmony_ci  session->options[OPT_RESOLUTION].descriptor.constraint_type =
1833141cc406Sopenharmony_ci    SANE_CONSTRAINT_WORD_LIST;
1834141cc406Sopenharmony_ci  session->options[OPT_RESOLUTION].descriptor.constraint.word_list = dpi_list;
1835141cc406Sopenharmony_ci
1836141cc406Sopenharmony_ci  /* initial value is lowest available dpi */
1837141cc406Sopenharmony_ci  session->options[OPT_RESOLUTION].value.w = min;
1838141cc406Sopenharmony_ci
1839141cc406Sopenharmony_ci  /* "Geometry" group: */
1840141cc406Sopenharmony_ci  session->options[OPT_GEOMETRY_GROUP].descriptor.title = SANE_TITLE_GEOMETRY;
1841141cc406Sopenharmony_ci  session->options[OPT_GEOMETRY_GROUP].descriptor.name = SANE_NAME_GEOMETRY;
1842141cc406Sopenharmony_ci  session->options[OPT_GEOMETRY_GROUP].descriptor.desc = SANE_DESC_GEOMETRY;
1843141cc406Sopenharmony_ci  session->options[OPT_GEOMETRY_GROUP].descriptor.type = SANE_TYPE_GROUP;
1844141cc406Sopenharmony_ci  session->options[OPT_GEOMETRY_GROUP].descriptor.cap = SANE_CAP_ADVANCED;
1845141cc406Sopenharmony_ci  session->options[OPT_GEOMETRY_GROUP].descriptor.size = 0;
1846141cc406Sopenharmony_ci  session->options[OPT_GEOMETRY_GROUP].descriptor.constraint_type =
1847141cc406Sopenharmony_ci    SANE_CONSTRAINT_NONE;
1848141cc406Sopenharmony_ci
1849141cc406Sopenharmony_ci  /* adapt the constraint range to the detected model */
1850141cc406Sopenharmony_ci  x_range.max = model->x_size;
1851141cc406Sopenharmony_ci  y_range.max = model->y_size;
1852141cc406Sopenharmony_ci
1853141cc406Sopenharmony_ci  /* top-left x */
1854141cc406Sopenharmony_ci  session->options[OPT_TL_X].descriptor.name = SANE_NAME_SCAN_TL_X;
1855141cc406Sopenharmony_ci  session->options[OPT_TL_X].descriptor.title = SANE_TITLE_SCAN_TL_X;
1856141cc406Sopenharmony_ci  session->options[OPT_TL_X].descriptor.desc = SANE_DESC_SCAN_TL_X;
1857141cc406Sopenharmony_ci  session->options[OPT_TL_X].descriptor.type = SANE_TYPE_FIXED;
1858141cc406Sopenharmony_ci  session->options[OPT_TL_X].descriptor.cap |= SANE_CAP_AUTOMATIC;
1859141cc406Sopenharmony_ci  session->options[OPT_TL_X].descriptor.unit = SANE_UNIT_MM;
1860141cc406Sopenharmony_ci  session->options[OPT_TL_X].descriptor.constraint_type =
1861141cc406Sopenharmony_ci    SANE_CONSTRAINT_RANGE;
1862141cc406Sopenharmony_ci  session->options[OPT_TL_X].descriptor.constraint.range = &x_range;
1863141cc406Sopenharmony_ci  session->options[OPT_TL_X].value.w = 0;
1864141cc406Sopenharmony_ci
1865141cc406Sopenharmony_ci  /* top-left y */
1866141cc406Sopenharmony_ci  session->options[OPT_TL_Y].descriptor.name = SANE_NAME_SCAN_TL_Y;
1867141cc406Sopenharmony_ci  session->options[OPT_TL_Y].descriptor.title = SANE_TITLE_SCAN_TL_Y;
1868141cc406Sopenharmony_ci  session->options[OPT_TL_Y].descriptor.desc = SANE_DESC_SCAN_TL_Y;
1869141cc406Sopenharmony_ci  session->options[OPT_TL_Y].descriptor.type = SANE_TYPE_FIXED;
1870141cc406Sopenharmony_ci  session->options[OPT_TL_Y].descriptor.cap |= SANE_CAP_AUTOMATIC;
1871141cc406Sopenharmony_ci  session->options[OPT_TL_Y].descriptor.unit = SANE_UNIT_MM;
1872141cc406Sopenharmony_ci  session->options[OPT_TL_Y].descriptor.constraint_type =
1873141cc406Sopenharmony_ci    SANE_CONSTRAINT_RANGE;
1874141cc406Sopenharmony_ci  session->options[OPT_TL_Y].descriptor.constraint.range = &y_range;
1875141cc406Sopenharmony_ci  session->options[OPT_TL_Y].value.w = 0;
1876141cc406Sopenharmony_ci
1877141cc406Sopenharmony_ci  /* bottom-right x */
1878141cc406Sopenharmony_ci  session->options[OPT_BR_X].descriptor.name = SANE_NAME_SCAN_BR_X;
1879141cc406Sopenharmony_ci  session->options[OPT_BR_X].descriptor.title = SANE_TITLE_SCAN_BR_X;
1880141cc406Sopenharmony_ci  session->options[OPT_BR_X].descriptor.desc = SANE_DESC_SCAN_BR_X;
1881141cc406Sopenharmony_ci  session->options[OPT_BR_X].descriptor.type = SANE_TYPE_FIXED;
1882141cc406Sopenharmony_ci  session->options[OPT_BR_X].descriptor.cap |= SANE_CAP_AUTOMATIC;
1883141cc406Sopenharmony_ci  session->options[OPT_BR_X].descriptor.unit = SANE_UNIT_MM;
1884141cc406Sopenharmony_ci  session->options[OPT_BR_X].descriptor.constraint_type =
1885141cc406Sopenharmony_ci    SANE_CONSTRAINT_RANGE;
1886141cc406Sopenharmony_ci  session->options[OPT_BR_X].descriptor.constraint.range = &x_range;
1887141cc406Sopenharmony_ci  session->options[OPT_BR_X].value.w = x_range.max;
1888141cc406Sopenharmony_ci
1889141cc406Sopenharmony_ci  /* bottom-right y */
1890141cc406Sopenharmony_ci  session->options[OPT_BR_Y].descriptor.name = SANE_NAME_SCAN_BR_Y;
1891141cc406Sopenharmony_ci  session->options[OPT_BR_Y].descriptor.title = SANE_TITLE_SCAN_BR_Y;
1892141cc406Sopenharmony_ci  session->options[OPT_BR_Y].descriptor.desc = SANE_DESC_SCAN_BR_Y;
1893141cc406Sopenharmony_ci  session->options[OPT_BR_Y].descriptor.type = SANE_TYPE_FIXED;
1894141cc406Sopenharmony_ci  session->options[OPT_BR_Y].descriptor.cap |= SANE_CAP_AUTOMATIC;
1895141cc406Sopenharmony_ci  session->options[OPT_BR_Y].descriptor.unit = SANE_UNIT_MM;
1896141cc406Sopenharmony_ci  session->options[OPT_BR_Y].descriptor.constraint_type =
1897141cc406Sopenharmony_ci    SANE_CONSTRAINT_RANGE;
1898141cc406Sopenharmony_ci  session->options[OPT_BR_Y].descriptor.constraint.range = &y_range;
1899141cc406Sopenharmony_ci  session->options[OPT_BR_Y].value.w = y_range.max;
1900141cc406Sopenharmony_ci
1901141cc406Sopenharmony_ci  /* sensor group */
1902141cc406Sopenharmony_ci  session->options[OPT_SENSOR_GROUP].descriptor.name = SANE_NAME_SENSORS;
1903141cc406Sopenharmony_ci  session->options[OPT_SENSOR_GROUP].descriptor.title = SANE_TITLE_SENSORS;
1904141cc406Sopenharmony_ci  session->options[OPT_SENSOR_GROUP].descriptor.desc = SANE_DESC_SENSORS;
1905141cc406Sopenharmony_ci  session->options[OPT_SENSOR_GROUP].descriptor.type = SANE_TYPE_GROUP;
1906141cc406Sopenharmony_ci  session->options[OPT_SENSOR_GROUP].descriptor.constraint_type =
1907141cc406Sopenharmony_ci    SANE_CONSTRAINT_NONE;
1908141cc406Sopenharmony_ci
1909141cc406Sopenharmony_ci  /* page loaded sensor */
1910141cc406Sopenharmony_ci  session->options[OPT_PAGE_LOADED_SW].descriptor.name =
1911141cc406Sopenharmony_ci    SANE_NAME_PAGE_LOADED;
1912141cc406Sopenharmony_ci  session->options[OPT_PAGE_LOADED_SW].descriptor.title =
1913141cc406Sopenharmony_ci    SANE_TITLE_PAGE_LOADED;
1914141cc406Sopenharmony_ci  session->options[OPT_PAGE_LOADED_SW].descriptor.desc =
1915141cc406Sopenharmony_ci    SANE_DESC_PAGE_LOADED;
1916141cc406Sopenharmony_ci  session->options[OPT_PAGE_LOADED_SW].descriptor.type = SANE_TYPE_BOOL;
1917141cc406Sopenharmony_ci  session->options[OPT_PAGE_LOADED_SW].descriptor.unit = SANE_UNIT_NONE;
1918141cc406Sopenharmony_ci  session->options[OPT_PAGE_LOADED_SW].descriptor.cap =
1919141cc406Sopenharmony_ci    SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
1920141cc406Sopenharmony_ci  session->options[OPT_PAGE_LOADED_SW].value.b = 0;
1921141cc406Sopenharmony_ci
1922141cc406Sopenharmony_ci  /* calibration needed */
1923141cc406Sopenharmony_ci  session->options[OPT_NEED_CALIBRATION_SW].descriptor.name =
1924141cc406Sopenharmony_ci    "need-calibration";
1925141cc406Sopenharmony_ci  session->options[OPT_NEED_CALIBRATION_SW].descriptor.title =
1926141cc406Sopenharmony_ci    SANE_I18N ("Need calibration");
1927141cc406Sopenharmony_ci  session->options[OPT_NEED_CALIBRATION_SW].descriptor.desc =
1928141cc406Sopenharmony_ci    SANE_I18N ("The scanner needs calibration for the current settings");
1929141cc406Sopenharmony_ci  session->options[OPT_NEED_CALIBRATION_SW].descriptor.type = SANE_TYPE_BOOL;
1930141cc406Sopenharmony_ci  session->options[OPT_NEED_CALIBRATION_SW].descriptor.unit = SANE_UNIT_NONE;
1931141cc406Sopenharmony_ci  session->options[OPT_NEED_CALIBRATION_SW].descriptor.cap =
1932141cc406Sopenharmony_ci    SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
1933141cc406Sopenharmony_ci  session->options[OPT_NEED_CALIBRATION_SW].value.b = 0;
1934141cc406Sopenharmony_ci
1935141cc406Sopenharmony_ci  /* button group */
1936141cc406Sopenharmony_ci  session->options[OPT_BUTTON_GROUP].descriptor.name = "Buttons";
1937141cc406Sopenharmony_ci  session->options[OPT_BUTTON_GROUP].descriptor.title = SANE_I18N ("Buttons");
1938141cc406Sopenharmony_ci  session->options[OPT_BUTTON_GROUP].descriptor.desc = SANE_I18N ("Buttons");
1939141cc406Sopenharmony_ci  session->options[OPT_BUTTON_GROUP].descriptor.type = SANE_TYPE_GROUP;
1940141cc406Sopenharmony_ci  session->options[OPT_BUTTON_GROUP].descriptor.constraint_type =
1941141cc406Sopenharmony_ci    SANE_CONSTRAINT_NONE;
1942141cc406Sopenharmony_ci
1943141cc406Sopenharmony_ci  /* calibrate button */
1944141cc406Sopenharmony_ci  session->options[OPT_CALIBRATE].descriptor.name = "calibrate";
1945141cc406Sopenharmony_ci  session->options[OPT_CALIBRATE].descriptor.title = SANE_I18N ("Calibrate");
1946141cc406Sopenharmony_ci  session->options[OPT_CALIBRATE].descriptor.desc =
1947141cc406Sopenharmony_ci    SANE_I18N ("Start calibration using special sheet");
1948141cc406Sopenharmony_ci  session->options[OPT_CALIBRATE].descriptor.type = SANE_TYPE_BUTTON;
1949141cc406Sopenharmony_ci  session->options[OPT_CALIBRATE].descriptor.unit = SANE_UNIT_NONE;
1950141cc406Sopenharmony_ci  session->options[OPT_CALIBRATE].descriptor.cap =
1951141cc406Sopenharmony_ci    SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED |
1952141cc406Sopenharmony_ci    SANE_CAP_AUTOMATIC;
1953141cc406Sopenharmony_ci  session->options[OPT_CALIBRATE].value.b = 0;
1954141cc406Sopenharmony_ci
1955141cc406Sopenharmony_ci  /* clear calibration cache button */
1956141cc406Sopenharmony_ci  session->options[OPT_CLEAR_CALIBRATION].descriptor.name = "clear";
1957141cc406Sopenharmony_ci  session->options[OPT_CLEAR_CALIBRATION].descriptor.title =
1958141cc406Sopenharmony_ci    SANE_I18N ("Clear calibration");
1959141cc406Sopenharmony_ci  session->options[OPT_CLEAR_CALIBRATION].descriptor.desc =
1960141cc406Sopenharmony_ci    SANE_I18N ("Clear calibration cache");
1961141cc406Sopenharmony_ci  session->options[OPT_CLEAR_CALIBRATION].descriptor.type = SANE_TYPE_BUTTON;
1962141cc406Sopenharmony_ci  session->options[OPT_CLEAR_CALIBRATION].descriptor.unit = SANE_UNIT_NONE;
1963141cc406Sopenharmony_ci  session->options[OPT_CLEAR_CALIBRATION].descriptor.cap =
1964141cc406Sopenharmony_ci    SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED |
1965141cc406Sopenharmony_ci    SANE_CAP_AUTOMATIC;
1966141cc406Sopenharmony_ci  session->options[OPT_CLEAR_CALIBRATION].value.b = 0;
1967141cc406Sopenharmony_ci
1968141cc406Sopenharmony_ci  /* until work on calibration isfinished */
1969141cc406Sopenharmony_ci  DISABLE (OPT_CALIBRATE);
1970141cc406Sopenharmony_ci  DISABLE (OPT_CLEAR_CALIBRATION);
1971141cc406Sopenharmony_ci
1972141cc406Sopenharmony_ci  DBG (DBG_proc, "init_options: exit\n");
1973141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1974141cc406Sopenharmony_ci}
1975141cc406Sopenharmony_ci
1976141cc406Sopenharmony_ci/** @brief physical probe of a device
1977141cc406Sopenharmony_ci * This function probes for a scanning device using the given name. If the
1978141cc406Sopenharmony_ci * device is managed, a model structure describing the device will be returned.
1979141cc406Sopenharmony_ci * @param devicename low level device to access to probe hardware
1980141cc406Sopenharmony_ci * @return NULL is the device is unsupported, or a model struct describing the
1981141cc406Sopenharmony_ci * device.
1982141cc406Sopenharmony_ci */
1983141cc406Sopenharmony_ciP5_Model *
1984141cc406Sopenharmony_ciprobe (const char *devicename)
1985141cc406Sopenharmony_ci{
1986141cc406Sopenharmony_ci  int fd;
1987141cc406Sopenharmony_ci
1988141cc406Sopenharmony_ci  /* open parallel port device */
1989141cc406Sopenharmony_ci  fd = open_pp (devicename);
1990141cc406Sopenharmony_ci  if (fd < 0)
1991141cc406Sopenharmony_ci    {
1992141cc406Sopenharmony_ci      DBG (DBG_error, "probe: failed to open '%s' device!\n", devicename);
1993141cc406Sopenharmony_ci      return NULL;
1994141cc406Sopenharmony_ci    }
1995141cc406Sopenharmony_ci
1996141cc406Sopenharmony_ci  /* now try to connect to scanner */
1997141cc406Sopenharmony_ci  if (connect (fd) != SANE_TRUE)
1998141cc406Sopenharmony_ci    {
1999141cc406Sopenharmony_ci      DBG (DBG_error, "probe: failed to connect!\n");
2000141cc406Sopenharmony_ci      close_pp (fd);
2001141cc406Sopenharmony_ci      return NULL;
2002141cc406Sopenharmony_ci    }
2003141cc406Sopenharmony_ci
2004141cc406Sopenharmony_ci  /* set up for memory test */
2005141cc406Sopenharmony_ci  write_reg (fd, REG1, 0x00);
2006141cc406Sopenharmony_ci  write_reg (fd, REG7, 0x00);
2007141cc406Sopenharmony_ci  write_reg (fd, REG0, 0x00);
2008141cc406Sopenharmony_ci  write_reg (fd, REG1, 0x00);
2009141cc406Sopenharmony_ci  write_reg (fd, REGF, 0x80);
2010141cc406Sopenharmony_ci  if (memtest (fd, 0x0100) != SANE_TRUE)
2011141cc406Sopenharmony_ci    {
2012141cc406Sopenharmony_ci      disconnect (fd);
2013141cc406Sopenharmony_ci      close_pp (fd);
2014141cc406Sopenharmony_ci      DBG (DBG_error, "probe: memory test failed!\n");
2015141cc406Sopenharmony_ci      return NULL;
2016141cc406Sopenharmony_ci    }
2017141cc406Sopenharmony_ci  else
2018141cc406Sopenharmony_ci    {
2019141cc406Sopenharmony_ci      DBG (DBG_info, "memtest() OK...\n");
2020141cc406Sopenharmony_ci    }
2021141cc406Sopenharmony_ci  write_reg (fd, REG7, 0x00);
2022141cc406Sopenharmony_ci
2023141cc406Sopenharmony_ci  /* check for document presence 0xC6: present, 0xC3 no document */
2024141cc406Sopenharmony_ci  test_document (fd);
2025141cc406Sopenharmony_ci
2026141cc406Sopenharmony_ci  /* release device and parport for next uses */
2027141cc406Sopenharmony_ci  disconnect (fd);
2028141cc406Sopenharmony_ci  close_pp (fd);
2029141cc406Sopenharmony_ci
2030141cc406Sopenharmony_ci  /* for there is only one supported model, so we use hardcoded values */
2031141cc406Sopenharmony_ci  DBG (DBG_proc, "probe: exit\n");
2032141cc406Sopenharmony_ci  return &pagepartner_model;
2033141cc406Sopenharmony_ci}
2034141cc406Sopenharmony_ci
2035141cc406Sopenharmony_ci
2036141cc406Sopenharmony_ci/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */
2037