summaryrefslogtreecommitdiff
path: root/backend/kvs1025.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/kvs1025.c')
-rw-r--r--backend/kvs1025.c456
1 files changed, 456 insertions, 0 deletions
diff --git a/backend/kvs1025.c b/backend/kvs1025.c
new file mode 100644
index 0000000..c0e1fa3
--- /dev/null
+++ b/backend/kvs1025.c
@@ -0,0 +1,456 @@
+/*
+ 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 1.04 documents (sane_dev.pdf)
+ for details */
+
+/* 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;
+}