1141cc406Sopenharmony_ci/*
2141cc406Sopenharmony_ci   Copyright (C) 2008, Panasonic Russia Ltd.
3141cc406Sopenharmony_ci   Copyright (C) 2010-2011, m. allan noah
4141cc406Sopenharmony_ci*/
5141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
6141cc406Sopenharmony_ci   Panasonic KV-S1020C / KV-S1025C USB scanners.
7141cc406Sopenharmony_ci*/
8141cc406Sopenharmony_ci
9141cc406Sopenharmony_ci#define DEBUG_NOT_STATIC
10141cc406Sopenharmony_ci
11141cc406Sopenharmony_ci#include "../include/sane/config.h"
12141cc406Sopenharmony_ci
13141cc406Sopenharmony_ci#include <errno.h>
14141cc406Sopenharmony_ci#include <fcntl.h>
15141cc406Sopenharmony_ci#include <limits.h>
16141cc406Sopenharmony_ci#include <signal.h>
17141cc406Sopenharmony_ci#include <stdio.h>
18141cc406Sopenharmony_ci#include <stdlib.h>
19141cc406Sopenharmony_ci#include <string.h>
20141cc406Sopenharmony_ci#include <sys/types.h>
21141cc406Sopenharmony_ci#include <sys/wait.h>
22141cc406Sopenharmony_ci#include <unistd.h>
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci#include "../include/sane/sane.h"
25141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
26141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
27141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
28141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
29141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
30141cc406Sopenharmony_ci#include "../include/lassert.h"
31141cc406Sopenharmony_ci
32141cc406Sopenharmony_ci#include "kvs1025.h"
33141cc406Sopenharmony_ci#include "kvs1025_low.h"
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h"
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_ci/* SANE backend operations, see SANE Standard for details
38141cc406Sopenharmony_ci   https://sane-project.gitlab.io/standard/ */
39141cc406Sopenharmony_ci
40141cc406Sopenharmony_ci/* Init the KV-S1025 SANE backend. This function must be called before any other
41141cc406Sopenharmony_ci   SANE function can be called. */
42141cc406Sopenharmony_ciSANE_Status
43141cc406Sopenharmony_cisane_init (SANE_Int * version_code,
44141cc406Sopenharmony_ci	   SANE_Auth_Callback __sane_unused__ authorize)
45141cc406Sopenharmony_ci{
46141cc406Sopenharmony_ci  SANE_Status status;
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci  DBG_INIT ();
49141cc406Sopenharmony_ci
50141cc406Sopenharmony_ci  DBG (DBG_sane_init, "sane_init\n");
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ci  DBG (DBG_error,
53141cc406Sopenharmony_ci       "This is panasonic KV-S1020C / KV-S1025C version %d.%d build %d\n",
54141cc406Sopenharmony_ci       SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, V_BUILD);
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci  if (version_code)
57141cc406Sopenharmony_ci    {
58141cc406Sopenharmony_ci      *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, V_BUILD);
59141cc406Sopenharmony_ci    }
60141cc406Sopenharmony_ci
61141cc406Sopenharmony_ci  /* Initialize USB */
62141cc406Sopenharmony_ci  sanei_usb_init ();
63141cc406Sopenharmony_ci
64141cc406Sopenharmony_ci  status = kv_enum_devices ();
65141cc406Sopenharmony_ci  if (status)
66141cc406Sopenharmony_ci    return status;
67141cc406Sopenharmony_ci
68141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_init: leave\n");
69141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
70141cc406Sopenharmony_ci}
71141cc406Sopenharmony_ci
72141cc406Sopenharmony_ci/* Terminate the KV-S1025 SANE backend */
73141cc406Sopenharmony_civoid
74141cc406Sopenharmony_cisane_exit (void)
75141cc406Sopenharmony_ci{
76141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_exit: enter\n");
77141cc406Sopenharmony_ci
78141cc406Sopenharmony_ci  kv_exit ();
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_exit: exit\n");
81141cc406Sopenharmony_ci}
82141cc406Sopenharmony_ci
83141cc406Sopenharmony_ci/* Get device list */
84141cc406Sopenharmony_ciSANE_Status
85141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list,
86141cc406Sopenharmony_ci		  SANE_Bool __sane_unused__ local_only)
87141cc406Sopenharmony_ci{
88141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_devices: enter\n");
89141cc406Sopenharmony_ci  kv_get_devices_list (device_list);
90141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_devices: leave\n");
91141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
92141cc406Sopenharmony_ci}
93141cc406Sopenharmony_ci
94141cc406Sopenharmony_ci/* Open device, return the device handle */
95141cc406Sopenharmony_ciSANE_Status
96141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
97141cc406Sopenharmony_ci{
98141cc406Sopenharmony_ci  return kv_open_by_name (devicename, handle);
99141cc406Sopenharmony_ci}
100141cc406Sopenharmony_ci
101141cc406Sopenharmony_ci/* Close device */
102141cc406Sopenharmony_civoid
103141cc406Sopenharmony_cisane_close (SANE_Handle handle)
104141cc406Sopenharmony_ci{
105141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_close: enter\n");
106141cc406Sopenharmony_ci  kv_close ((PKV_DEV) handle);
107141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_close: leave\n");
108141cc406Sopenharmony_ci}
109141cc406Sopenharmony_ci
110141cc406Sopenharmony_ci/* Get option descriptor */
111141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
112141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
113141cc406Sopenharmony_ci{
114141cc406Sopenharmony_ci  return kv_get_option_descriptor ((PKV_DEV) handle, option);
115141cc406Sopenharmony_ci}
116141cc406Sopenharmony_ci
117141cc406Sopenharmony_ci/* Control option */
118141cc406Sopenharmony_ciSANE_Status
119141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option,
120141cc406Sopenharmony_ci		     SANE_Action action, void *val, SANE_Int * info)
121141cc406Sopenharmony_ci{
122141cc406Sopenharmony_ci  return kv_control_option ((PKV_DEV) handle, option, action, val, info);
123141cc406Sopenharmony_ci}
124141cc406Sopenharmony_ci
125141cc406Sopenharmony_ci/* Get scan parameters */
126141cc406Sopenharmony_ciSANE_Status
127141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
128141cc406Sopenharmony_ci{
129141cc406Sopenharmony_ci  PKV_DEV dev = (PKV_DEV) handle;
130141cc406Sopenharmony_ci
131141cc406Sopenharmony_ci  int side = dev->current_side == SIDE_FRONT ? 0 : 1;
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_parameters: enter\n");
134141cc406Sopenharmony_ci
135141cc406Sopenharmony_ci  if (!(dev->scanning))
136141cc406Sopenharmony_ci    {
137141cc406Sopenharmony_ci      /* Setup the parameters for the scan. (guessed value) */
138141cc406Sopenharmony_ci      int resolution = dev->val[OPT_RESOLUTION].w;
139141cc406Sopenharmony_ci      int width, length, depth = kv_get_depth (kv_get_mode (dev));;
140141cc406Sopenharmony_ci
141141cc406Sopenharmony_ci      DBG (DBG_proc, "sane_get_parameters: initial settings\n");
142141cc406Sopenharmony_ci      kv_calc_paper_size (dev, &width, &length);
143141cc406Sopenharmony_ci
144141cc406Sopenharmony_ci      DBG (DBG_error, "Resolution = %d\n", resolution);
145141cc406Sopenharmony_ci      DBG (DBG_error, "Paper width = %d, height = %d\n", width, length);
146141cc406Sopenharmony_ci
147141cc406Sopenharmony_ci      /* Prepare the parameters for the caller. */
148141cc406Sopenharmony_ci      dev->params[0].format = kv_get_mode (dev) == SM_COLOR ?
149141cc406Sopenharmony_ci	SANE_FRAME_RGB : SANE_FRAME_GRAY;
150141cc406Sopenharmony_ci
151141cc406Sopenharmony_ci      dev->params[0].last_frame = SANE_TRUE;
152141cc406Sopenharmony_ci      dev->params[0].pixels_per_line = ((width * resolution) / 1200) & (~0xf);
153141cc406Sopenharmony_ci
154141cc406Sopenharmony_ci      dev->params[0].depth = depth > 8 ? 8 : depth;
155141cc406Sopenharmony_ci
156141cc406Sopenharmony_ci      dev->params[0].bytes_per_line =
157141cc406Sopenharmony_ci	(dev->params[0].pixels_per_line / 8) * depth;
158141cc406Sopenharmony_ci      dev->params[0].lines = (length * resolution) / 1200;
159141cc406Sopenharmony_ci
160141cc406Sopenharmony_ci      memcpy (&dev->params[1], &dev->params[0], sizeof (SANE_Parameters));
161141cc406Sopenharmony_ci    }
162141cc406Sopenharmony_ci
163141cc406Sopenharmony_ci  /* Return the current values. */
164141cc406Sopenharmony_ci  if (params)
165141cc406Sopenharmony_ci    *params = (dev->params[side]);
166141cc406Sopenharmony_ci
167141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_get_parameters: exit\n");
168141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
169141cc406Sopenharmony_ci}
170141cc406Sopenharmony_ci
171141cc406Sopenharmony_ci/* Start scanning */
172141cc406Sopenharmony_ciSANE_Status
173141cc406Sopenharmony_cisane_start (SANE_Handle handle)
174141cc406Sopenharmony_ci{
175141cc406Sopenharmony_ci  SANE_Status status;
176141cc406Sopenharmony_ci  PKV_DEV dev = (PKV_DEV) handle;
177141cc406Sopenharmony_ci  SANE_Bool dev_ready;
178141cc406Sopenharmony_ci  KV_CMD_RESPONSE rs;
179141cc406Sopenharmony_ci
180141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: enter\n");
181141cc406Sopenharmony_ci  if (!dev->scanning)
182141cc406Sopenharmony_ci    {
183141cc406Sopenharmony_ci      /* open device */
184141cc406Sopenharmony_ci      if (!kv_already_open (dev))
185141cc406Sopenharmony_ci	{
186141cc406Sopenharmony_ci	  DBG (DBG_proc, "sane_start: need to open device\n");
187141cc406Sopenharmony_ci	  status = kv_open (dev);
188141cc406Sopenharmony_ci	  if (status)
189141cc406Sopenharmony_ci	    {
190141cc406Sopenharmony_ci	      return status;
191141cc406Sopenharmony_ci	    }
192141cc406Sopenharmony_ci	}
193141cc406Sopenharmony_ci      /* Begin scan */
194141cc406Sopenharmony_ci      DBG (DBG_proc, "sane_start: begin scan\n");
195141cc406Sopenharmony_ci
196141cc406Sopenharmony_ci      /* Get necessary parameters */
197141cc406Sopenharmony_ci      sane_get_parameters (dev, NULL);
198141cc406Sopenharmony_ci
199141cc406Sopenharmony_ci      dev->current_page = 0;
200141cc406Sopenharmony_ci      dev->current_side = SIDE_FRONT;
201141cc406Sopenharmony_ci
202141cc406Sopenharmony_ci      /* The scanner must be ready. */
203141cc406Sopenharmony_ci      status = CMD_test_unit_ready (dev, &dev_ready);
204141cc406Sopenharmony_ci      if (status || !dev_ready)
205141cc406Sopenharmony_ci	{
206141cc406Sopenharmony_ci	  return SANE_STATUS_DEVICE_BUSY;
207141cc406Sopenharmony_ci	}
208141cc406Sopenharmony_ci
209141cc406Sopenharmony_ci      if (!strcmp (dev->val[OPT_MANUALFEED].s, "off"))
210141cc406Sopenharmony_ci	{
211141cc406Sopenharmony_ci	  status = CMD_get_document_existanse (dev);
212141cc406Sopenharmony_ci	  if (status)
213141cc406Sopenharmony_ci	    {
214141cc406Sopenharmony_ci	      DBG (DBG_proc, "sane_start: exit with no more docs\n");
215141cc406Sopenharmony_ci	      return status;
216141cc406Sopenharmony_ci	    }
217141cc406Sopenharmony_ci	}
218141cc406Sopenharmony_ci
219141cc406Sopenharmony_ci      /* Set window */
220141cc406Sopenharmony_ci      status = CMD_reset_window (dev);
221141cc406Sopenharmony_ci      if (status)
222141cc406Sopenharmony_ci	{
223141cc406Sopenharmony_ci	  return status;
224141cc406Sopenharmony_ci	}
225141cc406Sopenharmony_ci
226141cc406Sopenharmony_ci      status = CMD_set_window (dev, SIDE_FRONT, &rs);
227141cc406Sopenharmony_ci      if (status)
228141cc406Sopenharmony_ci	{
229141cc406Sopenharmony_ci	  DBG (DBG_proc, "sane_start: error setting window\n");
230141cc406Sopenharmony_ci	  return status;
231141cc406Sopenharmony_ci	}
232141cc406Sopenharmony_ci
233141cc406Sopenharmony_ci      if (rs.status)
234141cc406Sopenharmony_ci	{
235141cc406Sopenharmony_ci	  DBG (DBG_proc, "sane_start: error setting window\n");
236141cc406Sopenharmony_ci	  DBG (DBG_proc,
237141cc406Sopenharmony_ci	       "sane_start: sense_key=0x%x, ASC=0x%x, ASCQ=0x%x\n",
238141cc406Sopenharmony_ci	       get_RS_sense_key (rs.sense),
239141cc406Sopenharmony_ci	       get_RS_ASC (rs.sense), get_RS_ASCQ (rs.sense));
240141cc406Sopenharmony_ci	  return SANE_STATUS_DEVICE_BUSY;
241141cc406Sopenharmony_ci	}
242141cc406Sopenharmony_ci
243141cc406Sopenharmony_ci      if (IS_DUPLEX (dev))
244141cc406Sopenharmony_ci	{
245141cc406Sopenharmony_ci	  status = CMD_set_window (dev, SIDE_BACK, &rs);
246141cc406Sopenharmony_ci
247141cc406Sopenharmony_ci	  if (status)
248141cc406Sopenharmony_ci	    {
249141cc406Sopenharmony_ci	      DBG (DBG_proc, "sane_start: error setting window\n");
250141cc406Sopenharmony_ci	      return status;
251141cc406Sopenharmony_ci	    }
252141cc406Sopenharmony_ci	  if (rs.status)
253141cc406Sopenharmony_ci	    {
254141cc406Sopenharmony_ci	      DBG (DBG_proc, "sane_start: error setting window\n");
255141cc406Sopenharmony_ci	      DBG (DBG_proc,
256141cc406Sopenharmony_ci		   "sane_start: sense_key=0x%x, "
257141cc406Sopenharmony_ci		   "ASC=0x%x, ASCQ=0x%x\n",
258141cc406Sopenharmony_ci		   get_RS_sense_key (rs.sense),
259141cc406Sopenharmony_ci		   get_RS_ASC (rs.sense), get_RS_ASCQ (rs.sense));
260141cc406Sopenharmony_ci	      return SANE_STATUS_INVAL;
261141cc406Sopenharmony_ci	    }
262141cc406Sopenharmony_ci	}
263141cc406Sopenharmony_ci
264141cc406Sopenharmony_ci      /* Scan */
265141cc406Sopenharmony_ci      status = CMD_scan (dev);
266141cc406Sopenharmony_ci      if (status)
267141cc406Sopenharmony_ci	{
268141cc406Sopenharmony_ci	  return status;
269141cc406Sopenharmony_ci	}
270141cc406Sopenharmony_ci
271141cc406Sopenharmony_ci      status = AllocateImageBuffer (dev);
272141cc406Sopenharmony_ci      if (status)
273141cc406Sopenharmony_ci	{
274141cc406Sopenharmony_ci	  return status;
275141cc406Sopenharmony_ci	}
276141cc406Sopenharmony_ci      dev->scanning = 1;
277141cc406Sopenharmony_ci    }
278141cc406Sopenharmony_ci  else
279141cc406Sopenharmony_ci    {
280141cc406Sopenharmony_ci      /* renew page */
281141cc406Sopenharmony_ci      if (IS_DUPLEX (dev))
282141cc406Sopenharmony_ci	{
283141cc406Sopenharmony_ci	  if (dev->current_side == SIDE_FRONT)
284141cc406Sopenharmony_ci	    {
285141cc406Sopenharmony_ci	      /* back image data already read, so just return */
286141cc406Sopenharmony_ci	      dev->current_side = SIDE_BACK;
287141cc406Sopenharmony_ci	      DBG (DBG_proc, "sane_start: duplex back\n");
288141cc406Sopenharmony_ci	      status = SANE_STATUS_GOOD;
289141cc406Sopenharmony_ci              goto cleanup;
290141cc406Sopenharmony_ci	    }
291141cc406Sopenharmony_ci	  else
292141cc406Sopenharmony_ci	    {
293141cc406Sopenharmony_ci	      dev->current_side = SIDE_FRONT;
294141cc406Sopenharmony_ci	      dev->current_page++;
295141cc406Sopenharmony_ci	    }
296141cc406Sopenharmony_ci	}
297141cc406Sopenharmony_ci      else
298141cc406Sopenharmony_ci	{
299141cc406Sopenharmony_ci	  dev->current_page++;
300141cc406Sopenharmony_ci	}
301141cc406Sopenharmony_ci    }
302141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: NOW SCANNING page\n");
303141cc406Sopenharmony_ci
304141cc406Sopenharmony_ci  /* Read image data */
305141cc406Sopenharmony_ci  status = ReadImageData (dev, dev->current_page);
306141cc406Sopenharmony_ci  if (status)
307141cc406Sopenharmony_ci    {
308141cc406Sopenharmony_ci      dev->scanning = 0;
309141cc406Sopenharmony_ci      return status;
310141cc406Sopenharmony_ci    }
311141cc406Sopenharmony_ci
312141cc406Sopenharmony_ci  /* Get picture element size */
313141cc406Sopenharmony_ci  {
314141cc406Sopenharmony_ci    int width, height;
315141cc406Sopenharmony_ci    status = CMD_read_pic_elements (dev, dev->current_page,
316141cc406Sopenharmony_ci				    SIDE_FRONT, &width, &height);
317141cc406Sopenharmony_ci    if (status)
318141cc406Sopenharmony_ci      return status;
319141cc406Sopenharmony_ci  }
320141cc406Sopenharmony_ci
321141cc406Sopenharmony_ci  if (IS_DUPLEX (dev))
322141cc406Sopenharmony_ci    {
323141cc406Sopenharmony_ci      int width, height;
324141cc406Sopenharmony_ci      status = CMD_read_pic_elements (dev, dev->current_page,
325141cc406Sopenharmony_ci				      SIDE_BACK, &width, &height);
326141cc406Sopenharmony_ci      if (status)
327141cc406Sopenharmony_ci	return status;
328141cc406Sopenharmony_ci    }
329141cc406Sopenharmony_ci
330141cc406Sopenharmony_ci  /* software based enhancement functions from sanei_magic */
331141cc406Sopenharmony_ci  /* these will modify the image, and adjust the params */
332141cc406Sopenharmony_ci  /* at this point, we are only looking at the front image */
333141cc406Sopenharmony_ci  /* of simplex or duplex data, back side has already exited */
334141cc406Sopenharmony_ci  /* so, we do both sides now, if required */
335141cc406Sopenharmony_ci  if (dev->val[OPT_SWDESKEW].w){
336141cc406Sopenharmony_ci    buffer_deskew(dev,SIDE_FRONT);
337141cc406Sopenharmony_ci  }
338141cc406Sopenharmony_ci  if (dev->val[OPT_SWCROP].w){
339141cc406Sopenharmony_ci    buffer_crop(dev,SIDE_FRONT);
340141cc406Sopenharmony_ci  }
341141cc406Sopenharmony_ci  if (dev->val[OPT_SWDESPECK].w){
342141cc406Sopenharmony_ci    buffer_despeck(dev,SIDE_FRONT);
343141cc406Sopenharmony_ci  }
344141cc406Sopenharmony_ci  if (dev->val[OPT_SWDEROTATE].w || dev->val[OPT_ROTATE].w){
345141cc406Sopenharmony_ci    buffer_rotate(dev,SIDE_FRONT);
346141cc406Sopenharmony_ci  }
347141cc406Sopenharmony_ci
348141cc406Sopenharmony_ci  if (IS_DUPLEX (dev)){
349141cc406Sopenharmony_ci    if (dev->val[OPT_SWDESKEW].w){
350141cc406Sopenharmony_ci      buffer_deskew(dev,SIDE_BACK);
351141cc406Sopenharmony_ci    }
352141cc406Sopenharmony_ci    if (dev->val[OPT_SWCROP].w){
353141cc406Sopenharmony_ci      buffer_crop(dev,SIDE_BACK);
354141cc406Sopenharmony_ci    }
355141cc406Sopenharmony_ci    if (dev->val[OPT_SWDESPECK].w){
356141cc406Sopenharmony_ci      buffer_despeck(dev,SIDE_BACK);
357141cc406Sopenharmony_ci    }
358141cc406Sopenharmony_ci    if (dev->val[OPT_SWDEROTATE].w || dev->val[OPT_ROTATE].w){
359141cc406Sopenharmony_ci      buffer_rotate(dev,SIDE_BACK);
360141cc406Sopenharmony_ci    }
361141cc406Sopenharmony_ci  }
362141cc406Sopenharmony_ci
363141cc406Sopenharmony_ci  cleanup:
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci  /* check if we need to skip this page */
366141cc406Sopenharmony_ci  if (dev->val[OPT_SWSKIP].w && buffer_isblank(dev,dev->current_side)){
367141cc406Sopenharmony_ci    DBG (DBG_proc, "sane_start: blank page, recurse\n");
368141cc406Sopenharmony_ci    return sane_start(handle);
369141cc406Sopenharmony_ci  }
370141cc406Sopenharmony_ci
371141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_start: exit\n");
372141cc406Sopenharmony_ci  return status;
373141cc406Sopenharmony_ci}
374141cc406Sopenharmony_ci
375141cc406Sopenharmony_ciSANE_Status
376141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf,
377141cc406Sopenharmony_ci	   SANE_Int max_len, SANE_Int * len)
378141cc406Sopenharmony_ci{
379141cc406Sopenharmony_ci  PKV_DEV dev = (PKV_DEV) handle;
380141cc406Sopenharmony_ci  int side = dev->current_side == SIDE_FRONT ? 0 : 1;
381141cc406Sopenharmony_ci
382141cc406Sopenharmony_ci  int size = max_len;
383141cc406Sopenharmony_ci  if (!dev->scanning)
384141cc406Sopenharmony_ci    return SANE_STATUS_EOF;
385141cc406Sopenharmony_ci
386141cc406Sopenharmony_ci  if (size > dev->img_size[side])
387141cc406Sopenharmony_ci    size = dev->img_size[side];
388141cc406Sopenharmony_ci
389141cc406Sopenharmony_ci  if (size == 0)
390141cc406Sopenharmony_ci    {
391141cc406Sopenharmony_ci      *len = size;
392141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
393141cc406Sopenharmony_ci    }
394141cc406Sopenharmony_ci
395141cc406Sopenharmony_ci  if (dev->val[OPT_INVERSE].w &&
396141cc406Sopenharmony_ci      (kv_get_mode (dev) == SM_BINARY || kv_get_mode (dev) == SM_DITHER))
397141cc406Sopenharmony_ci    {
398141cc406Sopenharmony_ci      int i;
399141cc406Sopenharmony_ci      unsigned char *p = dev->img_pt[side];
400141cc406Sopenharmony_ci      for (i = 0; i < size; i++)
401141cc406Sopenharmony_ci	{
402141cc406Sopenharmony_ci	  buf[i] = ~p[i];
403141cc406Sopenharmony_ci	}
404141cc406Sopenharmony_ci    }
405141cc406Sopenharmony_ci  else
406141cc406Sopenharmony_ci    {
407141cc406Sopenharmony_ci      memcpy (buf, dev->img_pt[side], size);
408141cc406Sopenharmony_ci    }
409141cc406Sopenharmony_ci
410141cc406Sopenharmony_ci  /*hexdump(DBG_error, "img data", buf, 128); */
411141cc406Sopenharmony_ci
412141cc406Sopenharmony_ci  dev->img_pt[side] += size;
413141cc406Sopenharmony_ci  dev->img_size[side] -= size;
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_read: %d bytes to read, "
416141cc406Sopenharmony_ci       "%d bytes read, EOF=%s  %d\n",
417141cc406Sopenharmony_ci       max_len, size, dev->img_size[side] == 0 ? "True" : "False", side);
418141cc406Sopenharmony_ci
419141cc406Sopenharmony_ci  if (len)
420141cc406Sopenharmony_ci    {
421141cc406Sopenharmony_ci      *len = size;
422141cc406Sopenharmony_ci    }
423141cc406Sopenharmony_ci  if (dev->img_size[side] == 0)
424141cc406Sopenharmony_ci    {
425141cc406Sopenharmony_ci      if (!strcmp (dev->val[OPT_FEEDER_MODE].s, "single"))
426141cc406Sopenharmony_ci	if ((IS_DUPLEX (dev) && side) || !IS_DUPLEX (dev))
427141cc406Sopenharmony_ci	  dev->scanning = 0;
428141cc406Sopenharmony_ci    }
429141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
430141cc406Sopenharmony_ci}
431141cc406Sopenharmony_ci
432141cc406Sopenharmony_civoid
433141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
434141cc406Sopenharmony_ci{
435141cc406Sopenharmony_ci  PKV_DEV dev = (PKV_DEV) handle;
436141cc406Sopenharmony_ci  DBG (DBG_proc, "sane_cancel: scan canceled.\n");
437141cc406Sopenharmony_ci  dev->scanning = 0;
438141cc406Sopenharmony_ci
439141cc406Sopenharmony_ci  kv_close (dev);
440141cc406Sopenharmony_ci}
441141cc406Sopenharmony_ci
442141cc406Sopenharmony_ciSANE_Status
443141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle h, SANE_Bool m)
444141cc406Sopenharmony_ci{
445141cc406Sopenharmony_ci  (void) h;
446141cc406Sopenharmony_ci  (void) m;
447141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
448141cc406Sopenharmony_ci}
449141cc406Sopenharmony_ci
450141cc406Sopenharmony_ciSANE_Status
451141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle h, SANE_Int * fd)
452141cc406Sopenharmony_ci{
453141cc406Sopenharmony_ci  (void) h;
454141cc406Sopenharmony_ci  (void) fd;
455141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
456141cc406Sopenharmony_ci}
457