kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			457 wiersze
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			457 wiersze
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
| /*
 | |
|    Copyright (C) 2008, Panasonic Russia Ltd.
 | |
|    Copyright (C) 2010-2011, m. allan noah
 | |
| */
 | |
| /* sane - Scanner Access Now Easy.
 | |
|    Panasonic KV-S1020C / KV-S1025C USB scanners.
 | |
| */
 | |
| 
 | |
| #define DEBUG_NOT_STATIC
 | |
| 
 | |
| #include "../include/sane/config.h"
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <fcntl.h>
 | |
| #include <limits.h>
 | |
| #include <signal.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/wait.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #include "../include/sane/sane.h"
 | |
| #include "../include/sane/saneopts.h"
 | |
| #include "../include/sane/sanei.h"
 | |
| #include "../include/sane/sanei_usb.h"
 | |
| #include "../include/sane/sanei_backend.h"
 | |
| #include "../include/sane/sanei_config.h"
 | |
| #include "../include/lassert.h"
 | |
| 
 | |
| #include "kvs1025.h"
 | |
| #include "kvs1025_low.h"
 | |
| 
 | |
| #include "../include/sane/sanei_debug.h"
 | |
| 
 | |
| /* SANE backend operations, see SANE Standard for details
 | |
|    https://sane-project.gitlab.io/standard/ */
 | |
| 
 | |
| /* Init the KV-S1025 SANE backend. This function must be called before any other
 | |
|    SANE function can be called. */
 | |
| SANE_Status
 | |
| sane_init (SANE_Int * version_code,
 | |
| 	   SANE_Auth_Callback __sane_unused__ authorize)
 | |
| {
 | |
|   SANE_Status status;
 | |
| 
 | |
|   DBG_INIT ();
 | |
| 
 | |
|   DBG (DBG_sane_init, "sane_init\n");
 | |
| 
 | |
|   DBG (DBG_error,
 | |
|        "This is panasonic KV-S1020C / KV-S1025C version %d.%d build %d\n",
 | |
|        V_MAJOR, V_MINOR, V_BUILD);
 | |
| 
 | |
|   if (version_code)
 | |
|     {
 | |
|       *version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, V_BUILD);
 | |
|     }
 | |
| 
 | |
|   /* Initialize USB */
 | |
|   sanei_usb_init ();
 | |
| 
 | |
|   status = kv_enum_devices ();
 | |
|   if (status)
 | |
|     return status;
 | |
| 
 | |
|   DBG (DBG_proc, "sane_init: leave\n");
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| /* Terminate the KV-S1025 SANE backend */
 | |
| void
 | |
| sane_exit (void)
 | |
| {
 | |
|   DBG (DBG_proc, "sane_exit: enter\n");
 | |
| 
 | |
|   kv_exit ();
 | |
| 
 | |
|   DBG (DBG_proc, "sane_exit: exit\n");
 | |
| }
 | |
| 
 | |
| /* Get device list */
 | |
| SANE_Status
 | |
| sane_get_devices (const SANE_Device *** device_list,
 | |
| 		  SANE_Bool __sane_unused__ local_only)
 | |
| {
 | |
|   DBG (DBG_proc, "sane_get_devices: enter\n");
 | |
|   kv_get_devices_list (device_list);
 | |
|   DBG (DBG_proc, "sane_get_devices: leave\n");
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| /* Open device, return the device handle */
 | |
| SANE_Status
 | |
| sane_open (SANE_String_Const devicename, SANE_Handle * handle)
 | |
| {
 | |
|   return kv_open_by_name (devicename, handle);
 | |
| }
 | |
| 
 | |
| /* Close device */
 | |
| void
 | |
| sane_close (SANE_Handle handle)
 | |
| {
 | |
|   DBG (DBG_proc, "sane_close: enter\n");
 | |
|   kv_close ((PKV_DEV) handle);
 | |
|   DBG (DBG_proc, "sane_close: leave\n");
 | |
| }
 | |
| 
 | |
| /* Get option descriptor */
 | |
| const SANE_Option_Descriptor *
 | |
| sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
 | |
| {
 | |
|   return kv_get_option_descriptor ((PKV_DEV) handle, option);
 | |
| }
 | |
| 
 | |
| /* Control option */
 | |
| SANE_Status
 | |
| sane_control_option (SANE_Handle handle, SANE_Int option,
 | |
| 		     SANE_Action action, void *val, SANE_Int * info)
 | |
| {
 | |
|   return kv_control_option ((PKV_DEV) handle, option, action, val, info);
 | |
| }
 | |
| 
 | |
| /* Get scan parameters */
 | |
| SANE_Status
 | |
| sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
 | |
| {
 | |
|   PKV_DEV dev = (PKV_DEV) handle;
 | |
| 
 | |
|   int side = dev->current_side == SIDE_FRONT ? 0 : 1;
 | |
| 
 | |
|   DBG (DBG_proc, "sane_get_parameters: enter\n");
 | |
| 
 | |
|   if (!(dev->scanning))
 | |
|     {
 | |
|       /* Setup the parameters for the scan. (guessed value) */
 | |
|       int resolution = dev->val[OPT_RESOLUTION].w;
 | |
|       int width, length, depth = kv_get_depth (kv_get_mode (dev));;
 | |
| 
 | |
|       DBG (DBG_proc, "sane_get_parameters: initial settings\n");
 | |
|       kv_calc_paper_size (dev, &width, &length);
 | |
| 
 | |
|       DBG (DBG_error, "Resolution = %d\n", resolution);
 | |
|       DBG (DBG_error, "Paper width = %d, height = %d\n", width, length);
 | |
| 
 | |
|       /* Prepare the parameters for the caller. */
 | |
|       dev->params[0].format = kv_get_mode (dev) == SM_COLOR ?
 | |
| 	SANE_FRAME_RGB : SANE_FRAME_GRAY;
 | |
| 
 | |
|       dev->params[0].last_frame = SANE_TRUE;
 | |
|       dev->params[0].pixels_per_line = ((width * resolution) / 1200) & (~0xf);
 | |
| 
 | |
|       dev->params[0].depth = depth > 8 ? 8 : depth;
 | |
| 
 | |
|       dev->params[0].bytes_per_line =
 | |
| 	(dev->params[0].pixels_per_line / 8) * depth;
 | |
|       dev->params[0].lines = (length * resolution) / 1200;
 | |
| 
 | |
|       memcpy (&dev->params[1], &dev->params[0], sizeof (SANE_Parameters));
 | |
|     }
 | |
| 
 | |
|   /* Return the current values. */
 | |
|   if (params)
 | |
|     *params = (dev->params[side]);
 | |
| 
 | |
|   DBG (DBG_proc, "sane_get_parameters: exit\n");
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| /* Start scanning */
 | |
| SANE_Status
 | |
| sane_start (SANE_Handle handle)
 | |
| {
 | |
|   SANE_Status status;
 | |
|   PKV_DEV dev = (PKV_DEV) handle;
 | |
|   SANE_Bool dev_ready;
 | |
|   KV_CMD_RESPONSE rs;
 | |
| 
 | |
|   DBG (DBG_proc, "sane_start: enter\n");
 | |
|   if (!dev->scanning)
 | |
|     {
 | |
|       /* open device */
 | |
|       if (!kv_already_open (dev))
 | |
| 	{
 | |
| 	  DBG (DBG_proc, "sane_start: need to open device\n");
 | |
| 	  status = kv_open (dev);
 | |
| 	  if (status)
 | |
| 	    {
 | |
| 	      return status;
 | |
| 	    }
 | |
| 	}
 | |
|       /* Begin scan */
 | |
|       DBG (DBG_proc, "sane_start: begin scan\n");
 | |
| 
 | |
|       /* Get necessary parameters */
 | |
|       sane_get_parameters (dev, NULL);
 | |
| 
 | |
|       dev->current_page = 0;
 | |
|       dev->current_side = SIDE_FRONT;
 | |
| 
 | |
|       /* The scanner must be ready. */
 | |
|       status = CMD_test_unit_ready (dev, &dev_ready);
 | |
|       if (status || !dev_ready)
 | |
| 	{
 | |
| 	  return SANE_STATUS_DEVICE_BUSY;
 | |
| 	}
 | |
| 
 | |
|       if (!strcmp (dev->val[OPT_MANUALFEED].s, "off"))
 | |
| 	{
 | |
| 	  status = CMD_get_document_existanse (dev);
 | |
| 	  if (status)
 | |
| 	    {
 | |
| 	      DBG (DBG_proc, "sane_start: exit with no more docs\n");
 | |
| 	      return status;
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|       /* Set window */
 | |
|       status = CMD_reset_window (dev);
 | |
|       if (status)
 | |
| 	{
 | |
| 	  return status;
 | |
| 	}
 | |
| 
 | |
|       status = CMD_set_window (dev, SIDE_FRONT, &rs);
 | |
|       if (status)
 | |
| 	{
 | |
| 	  DBG (DBG_proc, "sane_start: error setting window\n");
 | |
| 	  return status;
 | |
| 	}
 | |
| 
 | |
|       if (rs.status)
 | |
| 	{
 | |
| 	  DBG (DBG_proc, "sane_start: error setting window\n");
 | |
| 	  DBG (DBG_proc,
 | |
| 	       "sane_start: sense_key=0x%x, ASC=0x%x, ASCQ=0x%x\n",
 | |
| 	       get_RS_sense_key (rs.sense),
 | |
| 	       get_RS_ASC (rs.sense), get_RS_ASCQ (rs.sense));
 | |
| 	  return SANE_STATUS_DEVICE_BUSY;
 | |
| 	}
 | |
| 
 | |
|       if (IS_DUPLEX (dev))
 | |
| 	{
 | |
| 	  status = CMD_set_window (dev, SIDE_BACK, &rs);
 | |
| 
 | |
| 	  if (status)
 | |
| 	    {
 | |
| 	      DBG (DBG_proc, "sane_start: error setting window\n");
 | |
| 	      return status;
 | |
| 	    }
 | |
| 	  if (rs.status)
 | |
| 	    {
 | |
| 	      DBG (DBG_proc, "sane_start: error setting window\n");
 | |
| 	      DBG (DBG_proc,
 | |
| 		   "sane_start: sense_key=0x%x, "
 | |
| 		   "ASC=0x%x, ASCQ=0x%x\n",
 | |
| 		   get_RS_sense_key (rs.sense),
 | |
| 		   get_RS_ASC (rs.sense), get_RS_ASCQ (rs.sense));
 | |
| 	      return SANE_STATUS_INVAL;
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|       /* Scan */
 | |
|       status = CMD_scan (dev);
 | |
|       if (status)
 | |
| 	{
 | |
| 	  return status;
 | |
| 	}
 | |
| 
 | |
|       status = AllocateImageBuffer (dev);
 | |
|       if (status)
 | |
| 	{
 | |
| 	  return status;
 | |
| 	}
 | |
|       dev->scanning = 1;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       /* renew page */
 | |
|       if (IS_DUPLEX (dev))
 | |
| 	{
 | |
| 	  if (dev->current_side == SIDE_FRONT)
 | |
| 	    {
 | |
| 	      /* back image data already read, so just return */
 | |
| 	      dev->current_side = SIDE_BACK;
 | |
| 	      DBG (DBG_proc, "sane_start: duplex back\n");
 | |
| 	      status = SANE_STATUS_GOOD;
 | |
|               goto cleanup;
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      dev->current_side = SIDE_FRONT;
 | |
| 	      dev->current_page++;
 | |
| 	    }
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  dev->current_page++;
 | |
| 	}
 | |
|     }
 | |
|   DBG (DBG_proc, "sane_start: NOW SCANNING page\n");
 | |
| 
 | |
|   /* Read image data */
 | |
|   status = ReadImageData (dev, dev->current_page);
 | |
|   if (status)
 | |
|     {
 | |
|       dev->scanning = 0;
 | |
|       return status;
 | |
|     }
 | |
| 
 | |
|   /* Get picture element size */
 | |
|   {
 | |
|     int width, height;
 | |
|     status = CMD_read_pic_elements (dev, dev->current_page,
 | |
| 				    SIDE_FRONT, &width, &height);
 | |
|     if (status)
 | |
|       return status;
 | |
|   }
 | |
| 
 | |
|   if (IS_DUPLEX (dev))
 | |
|     {
 | |
|       int width, height;
 | |
|       status = CMD_read_pic_elements (dev, dev->current_page,
 | |
| 				      SIDE_BACK, &width, &height);
 | |
|       if (status)
 | |
| 	return status;
 | |
|     }
 | |
| 
 | |
|   /* software based enhancement functions from sanei_magic */
 | |
|   /* these will modify the image, and adjust the params */
 | |
|   /* at this point, we are only looking at the front image */
 | |
|   /* of simplex or duplex data, back side has already exited */
 | |
|   /* so, we do both sides now, if required */
 | |
|   if (dev->val[OPT_SWDESKEW].w){
 | |
|     buffer_deskew(dev,SIDE_FRONT);
 | |
|   }
 | |
|   if (dev->val[OPT_SWCROP].w){
 | |
|     buffer_crop(dev,SIDE_FRONT);
 | |
|   }
 | |
|   if (dev->val[OPT_SWDESPECK].w){
 | |
|     buffer_despeck(dev,SIDE_FRONT);
 | |
|   }
 | |
|   if (dev->val[OPT_SWDEROTATE].w || dev->val[OPT_ROTATE].w){
 | |
|     buffer_rotate(dev,SIDE_FRONT);
 | |
|   }
 | |
| 
 | |
|   if (IS_DUPLEX (dev)){
 | |
|     if (dev->val[OPT_SWDESKEW].w){
 | |
|       buffer_deskew(dev,SIDE_BACK);
 | |
|     }
 | |
|     if (dev->val[OPT_SWCROP].w){
 | |
|       buffer_crop(dev,SIDE_BACK);
 | |
|     }
 | |
|     if (dev->val[OPT_SWDESPECK].w){
 | |
|       buffer_despeck(dev,SIDE_BACK);
 | |
|     }
 | |
|     if (dev->val[OPT_SWDEROTATE].w || dev->val[OPT_ROTATE].w){
 | |
|       buffer_rotate(dev,SIDE_BACK);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   cleanup:
 | |
| 
 | |
|   /* check if we need to skip this page */
 | |
|   if (dev->val[OPT_SWSKIP].w && buffer_isblank(dev,dev->current_side)){
 | |
|     DBG (DBG_proc, "sane_start: blank page, recurse\n");
 | |
|     return sane_start(handle);
 | |
|   }
 | |
| 
 | |
|   DBG (DBG_proc, "sane_start: exit\n");
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| sane_read (SANE_Handle handle, SANE_Byte * buf,
 | |
| 	   SANE_Int max_len, SANE_Int * len)
 | |
| {
 | |
|   PKV_DEV dev = (PKV_DEV) handle;
 | |
|   int side = dev->current_side == SIDE_FRONT ? 0 : 1;
 | |
| 
 | |
|   int size = max_len;
 | |
|   if (!dev->scanning)
 | |
|     return SANE_STATUS_EOF;
 | |
| 
 | |
|   if (size > dev->img_size[side])
 | |
|     size = dev->img_size[side];
 | |
| 
 | |
|   if (size == 0)
 | |
|     {
 | |
|       *len = size;
 | |
|       return SANE_STATUS_EOF;
 | |
|     }
 | |
| 
 | |
|   if (dev->val[OPT_INVERSE].w &&
 | |
|       (kv_get_mode (dev) == SM_BINARY || kv_get_mode (dev) == SM_DITHER))
 | |
|     {
 | |
|       int i;
 | |
|       unsigned char *p = dev->img_pt[side];
 | |
|       for (i = 0; i < size; i++)
 | |
| 	{
 | |
| 	  buf[i] = ~p[i];
 | |
| 	}
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       memcpy (buf, dev->img_pt[side], size);
 | |
|     }
 | |
| 
 | |
|   /*hexdump(DBG_error, "img data", buf, 128); */
 | |
| 
 | |
|   dev->img_pt[side] += size;
 | |
|   dev->img_size[side] -= size;
 | |
| 
 | |
|   DBG (DBG_proc, "sane_read: %d bytes to read, "
 | |
|        "%d bytes read, EOF=%s  %d\n",
 | |
|        max_len, size, dev->img_size[side] == 0 ? "True" : "False", side);
 | |
| 
 | |
|   if (len)
 | |
|     {
 | |
|       *len = size;
 | |
|     }
 | |
|   if (dev->img_size[side] == 0)
 | |
|     {
 | |
|       if (!strcmp (dev->val[OPT_FEEDER_MODE].s, "single"))
 | |
| 	if ((IS_DUPLEX (dev) && side) || !IS_DUPLEX (dev))
 | |
| 	  dev->scanning = 0;
 | |
|     }
 | |
|   return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| void
 | |
| sane_cancel (SANE_Handle handle)
 | |
| {
 | |
|   PKV_DEV dev = (PKV_DEV) handle;
 | |
|   DBG (DBG_proc, "sane_cancel: scan canceled.\n");
 | |
|   dev->scanning = 0;
 | |
| 
 | |
|   kv_close (dev);
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| sane_set_io_mode (SANE_Handle h, SANE_Bool m)
 | |
| {
 | |
|   h=h;
 | |
|   m=m;
 | |
|   return SANE_STATUS_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| sane_get_select_fd (SANE_Handle h, SANE_Int * fd)
 | |
| {
 | |
|   h=h;
 | |
|   fd=fd;
 | |
|   return SANE_STATUS_UNSUPPORTED;
 | |
| }
 |