Adding new files for new kvs1025 backend

merge-requests/1/head
m. allan noah 2010-02-12 22:23:14 -05:00
rodzic 07cd144f72
commit 5d12e39b7c
11 zmienionych plików z 3839 dodań i 0 usunięć

412
backend/kvs1025.c 100644
Wyświetl plik

@ -0,0 +1,412 @@
/*
Copyright (C) 2008, Panasonic Russia Ltd.
*/
/* 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 <usb.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 SCSI version %d.%d build %d\n",
V_MAJOR, V_MINOR, V_BUILD);
DBG (DBG_error, "(C) 2007 by Tao Zhang\n");
if (version_code)
{
*version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, V_BUILD);
}
/* Initialize USB */
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 ()
{
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)
{
dev->current_side = SIDE_BACK;
/* return; image data already read */
DBG (DBG_proc, "sane_start: exit\n");
return SANE_STATUS_GOOD;
}
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;
}
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)
{
return SANE_STATUS_UNSUPPORTED;
}
SANE_Status
sane_get_select_fd (SANE_Handle h, SANE_Int * fd)
{
return SANE_STATUS_UNSUPPORTED;
}

Wyświetl plik

@ -0,0 +1,2 @@
usb "Panasonic KV-S1025C"
/dev/scanner

127
backend/kvs1025.h 100644
Wyświetl plik

@ -0,0 +1,127 @@
/*
Copyright (C) 2008, Panasonic Russia Ltd.
*/
/* sane - Scanner Access Now Easy.
Panasonic KV-S1020C / KV-S1025C USB scanners.
*/
#ifndef __KVS1025_H
#define __KVS1025_H
/* SANE backend name */
#ifdef BACKEND_NAME
#undef BACKEND_NAME
#endif
#define BACKEND_NAME kvs1025
/* Build version */
#define V_BUILD 1
/* Paper range supported -- MAX A4 */
#define KV_MAX_X_RANGE 210
#define KV_MAX_Y_RANGE 297
/* Round ULX, ULY, Width and Height to 16 Pixels */
#define KV_PIXEL_ROUND 19200
/* (XR * W / 1200) % 16 == 0 i.e. (XR * W) % 19200 == 0 */
/* MAX IULs per LINE */
#define KV_PIXEL_MAX 14064
/* Max 14064 pixels per line, 1/1200 inch each */
#define MM_PER_INCH 25.4
#define mmToIlu(mm) (((mm) * 1200) / MM_PER_INCH)
#define iluToMm(ilu) (((ilu) * MM_PER_INCH) / 1200)
/* Vendor defined options */
#define SANE_NAME_DUPLEX "duplex"
#define SANE_NAME_PAPER_SIZE "paper-size"
#define SANE_NAME_AUTOSEP "autoseparation"
#define SANE_NAME_LANDSCAPE "landscape"
#define SANE_NAME_INVERSE "inverse"
#define SANE_NAME_MIRROR "mirror"
#define SANE_NAME_LONGPAPER "longpaper"
#define SANE_NAME_LENGTHCTL "length-control"
#define SANE_NAME_MANUALFEED "manual-feed"
#define SANE_NAME_FEED_TIMEOUT "feed-timeout"
#define SANE_NAME_DBLFEED "double-feed"
#define SANE_TITLE_DUPLEX SANE_I18N("Duplex")
#define SANE_TITLE_PAPER_SIZE SANE_I18N("Paper size")
#define SANE_TITLE_AUTOSEP SANE_I18N("Automatic separation")
#define SANE_TITLE_LANDSCAPE SANE_I18N("Landscape")
#define SANE_TITLE_INVERSE SANE_I18N("Inverse Image")
#define SANE_TITLE_MIRROR SANE_I18N("Mirror image")
#define SANE_TITLE_LONGPAPER SANE_I18N("Long paper mode")
#define SANE_TITLE_LENGTHCTL SANE_I18N("Length control mode")
#define SANE_TITLE_MANUALFEED SANE_I18N("Manual feed mode")
#define SANE_TITLE_FEED_TIMEOUT SANE_I18N("Manual feed timeout")
#define SANE_TITLE_DBLFEED SANE_I18N("Double feed detection")
#define SANE_DESC_DUPLEX \
SANE_I18N("Enable Duplex (Dual-Sided) Scanning")
#define SANE_DESC_PAPER_SIZE \
SANE_I18N("Physical size of the paper in the ADF");
#define SANE_DESC_AUTOSEP \
SANE_I18N("Automatic separation")
#define SIDE_FRONT 0x00
#define SIDE_BACK 0x80
/* Debug levels.
* Should be common to all backends. */
#define DBG_error0 0
#define DBG_error 1
#define DBG_sense 2
#define DBG_warning 3
#define DBG_inquiry 4
#define DBG_info 5
#define DBG_info2 6
#define DBG_proc 7
#define DBG_read 8
#define DBG_sane_init 10
#define DBG_sane_proc 11
#define DBG_sane_info 12
#define DBG_sane_option 13
#define DBG_shortread 101
/* Prototypes of SANE backend functions, see kvs1025.c */
SANE_Status sane_init (SANE_Int * version_code,
SANE_Auth_Callback /* __sane_unused__ authorize */ );
void sane_exit ();
SANE_Status sane_get_devices (const SANE_Device *** device_list,
SANE_Bool /*__sane_unused__ local_only*/ );
SANE_Status sane_open (SANE_String_Const devicename, SANE_Handle * handle);
void sane_close (SANE_Handle handle);
const SANE_Option_Descriptor *sane_get_option_descriptor (SANE_Handle
handle,
SANE_Int option);
SANE_Status sane_control_option (SANE_Handle handle, SANE_Int option,
SANE_Action action, void *val,
SANE_Int * info);
SANE_Status sane_get_parameters (SANE_Handle handle,
SANE_Parameters * params);
SANE_Status sane_start (SANE_Handle handle);
SANE_Status sane_read (SANE_Handle handle, SANE_Byte * buf,
SANE_Int max_len, SANE_Int * len);
void sane_cancel (SANE_Handle handle);
SANE_Status sane_set_io_mode (SANE_Handle h, SANE_Bool m);
SANE_Status sane_get_select_fd (SANE_Handle h, SANE_Int * fd);
SANE_String_Const sane_strstatus (SANE_Status status);
#endif /* #ifndef __KVS1025_H */

Wyświetl plik

@ -0,0 +1,74 @@
/*
Copyright (C) 2008, Panasonic Russia Ltd.
*/
/* sane - Scanner Access Now Easy.
Panasonic KV-S1020C / KV-S1025C USB scanners.
*/
#ifndef KVS1025_CMDS_H
#define KVS1025_CMDS_H
/* Commands supported by the KV-S1020C / KV-S1025C scanner. */
#define SCSI_TEST_UNIT_READY 0x00
#define SCSI_INQUIRY 0x12
#define SCSI_SET_WINDOW 0x24
#define SCSI_SCAN 0x1B
#define SCSI_SEND_10 0x2A
#define SCSI_READ_10 0x28
#define SCSI_REQUEST_SENSE 0x03
#define SCSI_GET_BUFFER_STATUS 0x34
#define SCSI_SET_TIMEOUT 0xE1
typedef enum
{
KV_CMD_NONE = 0,
KV_CMD_IN = 0x81, /* scanner to pc */
KV_CMD_OUT = 0x02 /* pc to scanner */
} KV_CMD_DIRECTION; /* equals to endpoint address */
typedef struct
{
KV_CMD_DIRECTION direction;
unsigned char cdb[12];
int cdb_size;
int data_size;
void *data;
} KV_CMD_HEADER, *PKV_CMD_HEADER;
#define KV_CMD_TIMEOUT 10000
static inline int
getbitfield (unsigned char *pageaddr, int mask, int shift)
{
return ((*pageaddr >> shift) & mask);
}
/* defines for request sense return block */
#define get_RS_information_valid(b) getbitfield(b + 0x00, 1, 7)
#define get_RS_error_code(b) getbitfield(b + 0x00, 0x7f, 0)
#define get_RS_filemark(b) getbitfield(b + 0x02, 1, 7)
#define get_RS_EOM(b) getbitfield(b + 0x02, 1, 6)
#define get_RS_ILI(b) getbitfield(b + 0x02, 1, 5)
#define get_RS_sense_key(b) getbitfield(b + 0x02, 0x0f, 0)
#define get_RS_information(b) getnbyte(b+0x03, 4)
#define get_RS_additional_length(b) b[0x07]
#define get_RS_ASC(b) b[0x0c]
#define get_RS_ASCQ(b) b[0x0d]
#define get_RS_SKSV(b) getbitfield(b+0x0f,1,7)
typedef enum
{
KV_SUCCESS = 0,
KV_FAILED = 1,
KV_CHK_CONDITION = 2
} KV_STATUS;
typedef struct
{
KV_STATUS status;
unsigned char reserved[16];
unsigned char sense[18];
} KV_CMD_RESPONSE, *PKV_CMD_RESPONSE;
#endif /*#ifndef KVS1025_CMDS_H */

Wyświetl plik

@ -0,0 +1,970 @@
/*
Copyright (C) 2008, Panasonic Russia Ltd.
*/
/* sane - Scanner Access Now Easy.
Panasonic KV-S1020C / KV-S1025C USB scanners.
*/
#define DEBUG_DECLARE_ONLY
#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 <usb.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 "kvs1025_usb.h"
#include "../include/sane/sanei_debug.h"
/* Global storage */
PKV_DEV g_devices = NULL; /* Chain of devices */
const SANE_Device **g_devlist = NULL;
/* Static functions */
/* Free one device */
static void
kv_free (KV_DEV ** pdev)
{
KV_DEV *dev;
dev = *pdev;
if (dev == NULL)
return;
DBG (DBG_proc, "kv_free : enter\n");
kv_close (dev);
DBG (DBG_proc, "kv_free : free image buffer 0 \n");
if (dev->img_buffers[0])
free (dev->img_buffers[0]);
DBG (DBG_proc, "kv_free : free image buffer 1 \n");
if (dev->img_buffers[1])
free (dev->img_buffers[1]);
DBG (DBG_proc, "kv_free : free scsi device name\n");
if (dev->scsi_device_name)
free (dev->scsi_device_name);
DBG (DBG_proc, "kv_free : free SCSI buffer\n");
if (dev->buffer0)
free (dev->buffer0);
DBG (DBG_proc, "kv_free : free dev \n");
free (dev);
*pdev = NULL;
DBG (DBG_proc, "kv_free : exit\n");
}
/* Free all devices */
static void
kv_free_devices ()
{
PKV_DEV dev;
while (g_devices)
{
dev = g_devices;
g_devices = dev->next;
kv_free (&dev);
}
if (g_devlist)
{
free (g_devlist);
g_devlist = NULL;
}
}
/* Get all supported scanners, and store into g_scanners_supported */
SANE_Status
kv_enum_devices ()
{
SANE_Status status;
kv_free_devices ();
status = kv_usb_enum_devices ();
if (status)
{
kv_free_devices ();
}
return status;
}
/* Return devices list to the front end */
void
kv_get_devices_list (const SANE_Device *** devices_list)
{
*devices_list = g_devlist;
}
/* Close all open handles and clean up global storage */
void
kv_exit ()
{
kv_free_devices (); /* Free all devices */
kv_usb_cleanup (); /* Clean USB bus */
}
/* Open device by name */
SANE_Status
kv_open_by_name (SANE_String_Const devicename, SANE_Handle * handle)
{
PKV_DEV pd = g_devices;
DBG (DBG_proc, "sane_open: enter (dev_name=%s)\n", devicename);
while (pd)
{
if (strcmp (pd->sane.name, devicename) == 0)
{
if (kv_open (pd) == 0)
{
*handle = (SANE_Handle) pd;
DBG (DBG_proc, "sane_open: leave\n");
return SANE_STATUS_GOOD;
}
}
pd = pd->next;
}
DBG (DBG_proc, "sane_open: leave -- no device found\n");
return SANE_STATUS_UNSUPPORTED;
}
/* Open a device */
SANE_Status
kv_open (PKV_DEV dev)
{
SANE_Status status = SANE_STATUS_UNSUPPORTED;
int i;
#define RETRAY_NUM 3
if (dev->bus_mode == KV_USB_BUS)
{
status = kv_usb_open (dev);
}
if (status)
return status;
for (i = 0; i < RETRAY_NUM; i++)
{
SANE_Bool dev_ready;
status = CMD_test_unit_ready (dev, &dev_ready);
if (!status && dev_ready)
break;
}
if (status == 0)
{
/* Read device support info */
status = CMD_read_support_info (dev);
if (status == 0)
{
/* Init options */
kv_init_options (dev);
status = CMD_set_timeout (dev, dev->val[OPT_FEED_TIMEOUT].w);
}
}
dev->scanning = 0;
return status;
}
/* Check if device is already open */
SANE_Bool
kv_already_open (PKV_DEV dev)
{
SANE_Bool status = 0;
if (dev->bus_mode == KV_USB_BUS)
{
status = kv_usb_already_open (dev);
}
return status;
}
/* Close a device */
void
kv_close (PKV_DEV dev)
{
if (dev->bus_mode == KV_USB_BUS)
{
kv_usb_close (dev);
}
dev->scanning = 0;
}
/* Send command to a device */
SANE_Status
kv_send_command (PKV_DEV dev,
PKV_CMD_HEADER header, PKV_CMD_RESPONSE response)
{
SANE_Status status = SANE_STATUS_UNSUPPORTED;
if (dev->bus_mode == KV_USB_BUS)
{
if (dev->usb_handle == NULL)
{
DBG (DBG_error, "kv_send_command error: device not open.\n");
return SANE_STATUS_IO_ERROR;
}
status = kv_usb_send_command (dev->usb_handle, header, response);
}
return status;
}
/* Commands */
SANE_Status
CMD_test_unit_ready (PKV_DEV dev, SANE_Bool * ready)
{
SANE_Status status;
KV_CMD_HEADER hdr;
KV_CMD_RESPONSE rs;
DBG (DBG_proc, "CMD_test_unit_ready\n");
memset (&hdr, 0, sizeof (hdr));
hdr.direction = KV_CMD_NONE;
hdr.cdb[0] = SCSI_TEST_UNIT_READY;
hdr.cdb_size = 6;
status = kv_send_command (dev, &hdr, &rs);
if (status == 0)
{
*ready = (rs.status == KV_SUCCESS ? 1 : 0);
}
return status;
}
SANE_Status
CMD_set_timeout (PKV_DEV dev, SANE_Word timeout)
{
SANE_Status status;
KV_CMD_HEADER hdr;
KV_CMD_RESPONSE rs;
DBG (DBG_proc, "CMD_set_timeout\n");
memset (&hdr, 0, sizeof (hdr));
hdr.direction = KV_CMD_OUT;
hdr.cdb[0] = SCSI_SET_TIMEOUT;
hdr.cdb[2] = 0x8D;
hdr.cdb[8] = 0x2;
hdr.cdb_size = 10;
hdr.data = dev->buffer;
dev->buffer[0] = 0;
dev->buffer[1] = (SANE_Byte) timeout;
hdr.data_size = 2;
status = kv_send_command (dev, &hdr, &rs);
return status;
}
SANE_Status
CMD_read_support_info (PKV_DEV dev)
{
SANE_Status status;
KV_CMD_HEADER hdr;
KV_CMD_RESPONSE rs;
DBG (DBG_proc, "CMD_read_support_info\n");
memset (&hdr, 0, sizeof (hdr));
hdr.direction = KV_CMD_IN;
hdr.cdb_size = 10;
hdr.cdb[0] = SCSI_READ_10;
hdr.cdb[2] = 0x93;
Ito24 (32, &hdr.cdb[6]);
hdr.data = dev->buffer;
hdr.data_size = 32;
status = kv_send_command (dev, &hdr, &rs);
DBG (DBG_error, "test.\n");
if (status == 0)
{
if (rs.status == 0)
{
int min_x_res, min_y_res, max_x_res, max_y_res;
int step_x_res, step_y_res;
dev->support_info.memory_size
= (dev->buffer[2] << 8 | dev->buffer[3]);
min_x_res = (dev->buffer[4] << 8) | dev->buffer[5];
min_y_res = (dev->buffer[6] << 8) | dev->buffer[7];
max_x_res = (dev->buffer[8] << 8) | dev->buffer[9];
max_y_res = (dev->buffer[10] << 8) | dev->buffer[11];
step_x_res = (dev->buffer[12] << 8) | dev->buffer[13];
step_y_res = (dev->buffer[14] << 8) | dev->buffer[15];
dev->support_info.min_resolution =
min_x_res > min_y_res ? min_x_res : min_y_res;
dev->support_info.max_resolution =
max_x_res < max_y_res ? max_x_res : max_y_res;
dev->support_info.step_resolution =
step_x_res > step_y_res ? step_x_res : step_y_res;
dev->support_info.support_duplex =
((dev->buffer[0] & 0x08) == 0) ? 1 : 0;
dev->support_info.support_lamp =
((dev->buffer[23] & 0x80) != 0) ? 1 : 0;
dev->support_info.max_x_range = KV_MAX_X_RANGE;
dev->support_info.max_y_range = KV_MAX_Y_RANGE;
dev->x_range.min = dev->y_range.min = 0;
dev->x_range.max = SANE_FIX (dev->support_info.max_x_range);
dev->y_range.max = SANE_FIX (dev->support_info.max_y_range);
dev->x_range.quant = dev->y_range.quant = 0;
DBG (DBG_error,
"support_info.memory_size = %d (MB)\n",
dev->support_info.memory_size);
DBG (DBG_error,
"support_info.min_resolution = %d (DPI)\n",
dev->support_info.min_resolution);
DBG (DBG_error,
"support_info.max_resolution = %d (DPI)\n",
dev->support_info.max_resolution);
DBG (DBG_error,
"support_info.step_resolution = %d (DPI)\n",
dev->support_info.step_resolution);
DBG (DBG_error,
"support_info.support_duplex = %s\n",
dev->support_info.support_duplex ? "TRUE" : "FALSE");
DBG (DBG_error, "support_info.support_lamp = %s\n",
dev->support_info.support_lamp ? "TRUE" : "FALSE");
}
else
{
DBG (DBG_error, "Error in CMD_get_support_info, "
"sense_key=%d, ASC=%d, ASCQ=%d\n",
get_RS_sense_key (rs.sense),
get_RS_ASC (rs.sense), get_RS_ASCQ (rs.sense));
}
}
return status;
}
SANE_Status
CMD_scan (PKV_DEV dev)
{
SANE_Status status;
KV_CMD_HEADER hdr;
KV_CMD_RESPONSE rs;
DBG (DBG_proc, "CMD_scan\n");
memset (&hdr, 0, sizeof (hdr));
hdr.direction = KV_CMD_NONE;
hdr.cdb[0] = SCSI_SCAN;
hdr.cdb_size = 6;
status = kv_send_command (dev, &hdr, &rs);
if (status == 0 && rs.status != 0)
{
DBG (DBG_error,
"Error in CMD_scan, sense_key=%d, ASC=%d, ASCQ=%d\n",
get_RS_sense_key (rs.sense), get_RS_ASC (rs.sense),
get_RS_ASCQ (rs.sense));
}
return status;
}
SANE_Status
CMD_set_window (PKV_DEV dev, int side, PKV_CMD_RESPONSE rs)
{
unsigned char *window;
unsigned char *windowdata;
int size = 74;
KV_SCAN_MODE scan_mode;
KV_CMD_HEADER hdr;
DBG (DBG_proc, "CMD_set_window\n");
window = (unsigned char *) dev->buffer;
windowdata = window + 8;
memset (&hdr, 0, sizeof (hdr));
memset (window, 0, size);
Ito16 (66, &window[6]); /* Window descriptor block length */
/* Set window data */
scan_mode = kv_get_mode (dev);
kv_set_window_data (dev, scan_mode, side, windowdata);
hdr.direction = KV_CMD_OUT;
hdr.cdb_size = 10;
hdr.cdb[0] = SCSI_SET_WINDOW;
Ito24 (size, &hdr.cdb[6]);
hdr.data = window;
hdr.data_size = size;
hexdump (DBG_error, "window", window, size);
return kv_send_command (dev, &hdr, rs);
}
SANE_Status
CMD_reset_window (PKV_DEV dev)
{
KV_CMD_HEADER hdr;
KV_CMD_RESPONSE rs;
SANE_Status status;
DBG (DBG_proc, "CMD_reset_window\n");
memset (&hdr, 0, sizeof (hdr));
hdr.direction = KV_CMD_NONE;
hdr.cdb_size = 10;
hdr.cdb[0] = SCSI_SET_WINDOW;
status = kv_send_command (dev, &hdr, &rs);
if (rs.status != 0)
status = SANE_STATUS_INVAL;
return status;
}
SANE_Status
CMD_get_buff_status (PKV_DEV dev, int *front_size, int *back_size)
{
KV_CMD_HEADER hdr;
KV_CMD_RESPONSE rs;
SANE_Status status;
unsigned char *data = (unsigned char *) dev->buffer;
int size = 12;
memset (&hdr, 0, sizeof (hdr));
memset (data, 0, size);
hdr.direction = KV_CMD_IN;
hdr.cdb_size = 10;
hdr.cdb[0] = SCSI_GET_BUFFER_STATUS;
hdr.cdb[8] = size;
hdr.data = data;
hdr.data_size = size;
status = kv_send_command (dev, &hdr, &rs);
if (status == 0)
{
if (rs.status == KV_CHK_CONDITION)
return SANE_STATUS_NO_DOCS;
else
{
unsigned char *p = data + 4;
if (p[0] == SIDE_FRONT)
{
*front_size = (p[5] << 16) | (p[6] << 8) | p[7];
}
else
{
*back_size = (p[5] << 16) | (p[6] << 8) | p[7];
}
return SANE_STATUS_GOOD;
}
}
return status;
}
SANE_Status
CMD_wait_buff_status (PKV_DEV dev, int *front_size, int *back_size)
{
SANE_Status status = SANE_STATUS_GOOD;
int cnt = 0;
*front_size = 0;
*back_size = 0;
DBG (DBG_proc, "CMD_wait_buff_status: enter feed %s\n",
dev->val[OPT_MANUALFEED].s);
do
{
DBG (DBG_proc, "CMD_wait_buff_status: tray #%d of %d\n", cnt,
dev->val[OPT_FEED_TIMEOUT].w);
status = CMD_get_buff_status (dev, front_size, back_size);
sleep (1);
}
while (status == SANE_STATUS_GOOD && (*front_size == 0)
&& (*back_size == 0) && cnt++ < dev->val[OPT_FEED_TIMEOUT].w);
if (cnt > dev->val[OPT_FEED_TIMEOUT].w)
status = SANE_STATUS_NO_DOCS;
if (status == 0)
DBG (DBG_proc, "CMD_wait_buff_status: exit "
"front_size %d, back_size %d\n", *front_size, *back_size);
else
DBG (DBG_proc, "CMD_wait_buff_status: exit with no docs\n");
return status;
}
SANE_Status
CMD_read_pic_elements (PKV_DEV dev, int page, int side,
int *width, int *height)
{
SANE_Status status;
KV_CMD_HEADER hdr;
KV_CMD_RESPONSE rs;
DBG (DBG_proc, "CMD_read_pic_elements\n");
memset (&hdr, 0, sizeof (hdr));
hdr.direction = KV_CMD_IN;
hdr.cdb_size = 10;
hdr.cdb[0] = SCSI_READ_10;
hdr.cdb[2] = 0x80;
hdr.cdb[4] = page;
hdr.cdb[5] = side;
Ito24 (16, &hdr.cdb[6]);
hdr.data = dev->buffer;
hdr.data_size = 16;
status = kv_send_command (dev, &hdr, &rs);
if (status == 0)
{
if (rs.status == 0)
{
int s = side == SIDE_FRONT ? 0 : 1;
int depth = kv_get_depth (kv_get_mode (dev));
*width = B32TOI (dev->buffer);
*height = B32TOI (&dev->buffer[4]);
assert ((*width) % 8 == 0);
DBG (DBG_proc, "CMD_read_pic_elements: "
"Page %d, Side %s, W=%d, H=%d\n",
page, side == SIDE_FRONT ? "F" : "B", *width, *height);
dev->params[s].format = kv_get_mode (dev) == SM_COLOR ?
SANE_FRAME_RGB : SANE_FRAME_GRAY;
dev->params[s].last_frame = SANE_TRUE;
dev->params[s].depth = depth > 8 ? 8 : depth;
dev->params[s].lines = *height ? *height
: dev->val[OPT_LANDSCAPE].w ? (*width * 3) / 4 : (*width * 4) / 3;
dev->params[s].pixels_per_line = *width;
dev->params[s].bytes_per_line =
(dev->params[s].pixels_per_line / 8) * depth;
}
else
{
DBG (DBG_proc, "CMD_read_pic_elements: failed\n");
status = SANE_STATUS_INVAL;
}
}
return status;
}
SANE_Status
CMD_read_image (PKV_DEV dev, int page, int side,
unsigned char *buffer, int *psize, KV_CMD_RESPONSE * rs)
{
SANE_Status status;
KV_CMD_HEADER hdr;
int size = *psize;
DBG (DBG_proc, "CMD_read_image\n");
memset (&hdr, 0, sizeof (hdr));
hdr.direction = KV_CMD_IN;
hdr.cdb_size = 10;
hdr.cdb[0] = SCSI_READ_10;
hdr.cdb[4] = page;
hdr.cdb[5] = side;
Ito24 (size, &hdr.cdb[6]);
hdr.data = buffer;
hdr.data_size = size;
*psize = 0;
status = kv_send_command (dev, &hdr, rs);
if (status)
return status;
*psize = size;
if (rs->status == KV_CHK_CONDITION && get_RS_ILI (rs->sense))
{
int delta = B32TOI (&rs->sense[3]);
DBG (DBG_error, "size=%d, delta=0x%x (%d)\n", size, delta, delta);
*psize = size - delta;
}
DBG (DBG_error, "CMD_read_image: bytes requested=%d, read=%d\n",
size, *psize);
DBG (DBG_error, "CMD_read_image: ILI=%d, EOM=%d\n",
get_RS_ILI (rs->sense), get_RS_EOM (rs->sense));
return status;
}
SANE_Status
CMD_get_document_existanse (PKV_DEV dev)
{
SANE_Status status;
KV_CMD_HEADER hdr;
KV_CMD_RESPONSE rs;
DBG (DBG_proc, "CMD_get_document_existanse\n");
memset (&hdr, 0, sizeof (hdr));
hdr.direction = KV_CMD_IN;
hdr.cdb_size = 10;
hdr.cdb[0] = SCSI_READ_10;
hdr.cdb[2] = 0x81;
Ito24 (6, &hdr.cdb[6]);
hdr.data = dev->buffer;
hdr.data_size = 6;
status = kv_send_command (dev, &hdr, &rs);
if (status)
return status;
if (rs.status)
return SANE_STATUS_NO_DOCS;
if ((dev->buffer[0] & 0x20) != 0)
{
return SANE_STATUS_GOOD;
}
return SANE_STATUS_NO_DOCS;
}
SANE_Status
CMD_wait_document_existanse (PKV_DEV dev)
{
SANE_Status status;
KV_CMD_HEADER hdr;
KV_CMD_RESPONSE rs;
int cnt;
DBG (DBG_proc, "CMD_wait_document_existanse\n");
memset (&hdr, 0, sizeof (hdr));
hdr.direction = KV_CMD_IN;
hdr.cdb_size = 10;
hdr.cdb[0] = SCSI_READ_10;
hdr.cdb[2] = 0x81;
Ito24 (6, &hdr.cdb[6]);
hdr.data = dev->buffer;
hdr.data_size = 6;
for (cnt = 0; cnt < dev->val[OPT_FEED_TIMEOUT].w; cnt++)
{
DBG (DBG_proc, "CMD_wait_document_existanse: tray #%d of %d\n", cnt,
dev->val[OPT_FEED_TIMEOUT].w);
status = kv_send_command (dev, &hdr, &rs);
if (status)
return status;
if (rs.status)
return SANE_STATUS_NO_DOCS;
if ((dev->buffer[0] & 0x20) != 0)
{
return SANE_STATUS_GOOD;
}
else if (strcmp (dev->val[OPT_MANUALFEED].s, "off") == 0)
{
return SANE_STATUS_NO_DOCS;
}
sleep (1);
}
return SANE_STATUS_NO_DOCS;
}
SANE_Status
CMD_request_sense (PKV_DEV dev)
{
KV_CMD_HEADER hdr;
KV_CMD_RESPONSE rs;
DBG (DBG_proc, "CMD_request_sense\n");
memset (&hdr, 0, sizeof (hdr));
hdr.direction = KV_CMD_IN;
hdr.cdb[0] = SCSI_REQUEST_SENSE;
hdr.cdb[4] = 0x12;
hdr.cdb_size = 6;
hdr.data_size = 0x12;
hdr.data = dev->buffer;
return kv_send_command (dev, &hdr, &rs);
}
/* Scan routines */
/* Allocate image buffer for one page (1 or 2 sides) */
SANE_Status
AllocateImageBuffer (PKV_DEV dev)
{
int *size = dev->bytes_to_read;
int sides = IS_DUPLEX (dev) ? 2 : 1;
int i;
size[0] = dev->params[0].bytes_per_line * dev->params[0].lines;
size[1] = dev->params[1].bytes_per_line * dev->params[1].lines;
DBG (DBG_proc, "AllocateImageBuffer: enter\n");
for (i = 0; i < sides; i++)
{
SANE_Byte *p;
DBG (DBG_proc, "AllocateImageBuffer: size(%c)=%d\n",
i ? 'B' : 'F', size[i]);
if (dev->img_buffers[i] == NULL)
{
p = (SANE_Byte *) malloc (size[i]);
if (p == NULL)
{
return SANE_STATUS_NO_MEM;
}
dev->img_buffers[i] = p;
}
else
{
p = (SANE_Byte *) realloc (dev->img_buffers[i], size[i]);
if (p == NULL)
{
return SANE_STATUS_NO_MEM;
}
else
{
dev->img_buffers[i] = p;
}
}
}
DBG (DBG_proc, "AllocateImageBuffer: exit\n");
return SANE_STATUS_GOOD;
}
/* Read image data from scanner dev->img_buffers[0],
for the simplex page */
SANE_Status
ReadImageDataSimplex (PKV_DEV dev, int page)
{
int bytes_to_read = dev->bytes_to_read[0];
SANE_Byte *buffer = (SANE_Byte *) dev->buffer;
int buff_size = SCSI_BUFFER_SIZE;
SANE_Byte *pt = dev->img_buffers[0];
KV_CMD_RESPONSE rs;
dev->img_size[0] = 0;
dev->img_size[1] = 0;
/* read loop */
do
{
int size = buff_size;
SANE_Status status;
DBG (DBG_error, "Bytes left = %d\n", bytes_to_read);
status = CMD_read_image (dev, page, SIDE_FRONT, buffer, &size, &rs);
if (status)
{
return status;
}
if (rs.status)
{
if (get_RS_sense_key (rs.sense))
{
DBG (DBG_error, "Error reading image data, "
"sense_key=%d, ASC=%d, ASCQ=%d",
get_RS_sense_key (rs.sense),
get_RS_ASC (rs.sense), get_RS_ASCQ (rs.sense));
if (get_RS_sense_key (rs.sense) == 3)
{
if (!get_RS_ASCQ (rs.sense))
return SANE_STATUS_NO_DOCS;
return SANE_STATUS_JAMMED;
}
return SANE_STATUS_IO_ERROR;
}
}
/* copy data to image buffer */
if (size > bytes_to_read)
{
size = bytes_to_read;
}
if (size > 0)
{
memcpy (pt, buffer, size);
bytes_to_read -= size;
pt += size;
dev->img_size[0] += size;
}
}
while (!get_RS_EOM (rs.sense));
assert (pt == dev->img_buffers[0] + dev->img_size[0]);
DBG (DBG_error, "Image size = %d\n", dev->img_size[0]);
return SANE_STATUS_GOOD;
}
/* Read image data from scanner dev->img_buffers[0],
for the duplex page */
SANE_Status
ReadImageDataDuplex (PKV_DEV dev, int page)
{
int bytes_to_read[2];
SANE_Byte *buffer = (SANE_Byte *) dev->buffer;
int buff_size[2];
SANE_Byte *pt[2];
KV_CMD_RESPONSE rs;
int sides[2];
SANE_Bool eoms[2];
int current_side = 1;
bytes_to_read[0] = dev->bytes_to_read[0];
bytes_to_read[1] = dev->bytes_to_read[1];
pt[0] = dev->img_buffers[0];
pt[1] = dev->img_buffers[1];
sides[0] = SIDE_FRONT;
sides[1] = SIDE_BACK;
eoms[0] = eoms[1] = 0;
buff_size[0] = SCSI_BUFFER_SIZE;
buff_size[1] = SCSI_BUFFER_SIZE;
dev->img_size[0] = 0;
dev->img_size[1] = 0;
/* read loop */
do
{
int size = buff_size[current_side];
SANE_Status status;
DBG (DBG_error, "Bytes left (F) = %d\n", bytes_to_read[0]);
DBG (DBG_error, "Bytes left (B) = %d\n", bytes_to_read[1]);
status = CMD_read_image (dev, page, sides[current_side],
buffer, &size, &rs);
if (status)
{
return status;
}
if (rs.status)
{
if (get_RS_sense_key (rs.sense))
{
DBG (DBG_error, "Error reading image data, "
"sense_key=%d, ASC=%d, ASCQ=%d",
get_RS_sense_key (rs.sense),
get_RS_ASC (rs.sense), get_RS_ASCQ (rs.sense));
if (get_RS_sense_key (rs.sense) == 3)
{
if (!get_RS_ASCQ (rs.sense))
return SANE_STATUS_NO_DOCS;
return SANE_STATUS_JAMMED;
}
return SANE_STATUS_IO_ERROR;
}
}
/* copy data to image buffer */
if (size > bytes_to_read[current_side])
{
size = bytes_to_read[current_side];
}
if (size > 0)
{
memcpy (pt[current_side], buffer, size);
bytes_to_read[current_side] -= size;
pt[current_side] += size;
dev->img_size[current_side] += size;
}
if (rs.status)
{
if (get_RS_EOM (rs.sense))
{
eoms[current_side] = 1;
}
if (get_RS_ILI (rs.sense))
{
current_side++;
current_side &= 1;
}
}
}
while (eoms[0] == 0 || eoms[1] == 0);
DBG (DBG_error, "Image size (F) = %d\n", dev->img_size[0]);
DBG (DBG_error, "Image size (B) = %d\n", dev->img_size[1]);
assert (pt[0] == dev->img_buffers[0] + dev->img_size[0]);
assert (pt[1] == dev->img_buffers[1] + dev->img_size[1]);
return SANE_STATUS_GOOD;
}
/* Read image data for one page */
SANE_Status
ReadImageData (PKV_DEV dev, int page)
{
SANE_Status status;
DBG (DBG_proc, "Reading image data for page %d\n", page);
if (IS_DUPLEX (dev))
{
DBG (DBG_proc, "ReadImageData: Duplex\n", page);
status = ReadImageDataDuplex (dev, page);
}
else
{
DBG (DBG_proc, "ReadImageData: Simplex\n", page);
status = ReadImageDataSimplex (dev, page);
}
dev->img_pt[0] = dev->img_buffers[0];
dev->img_pt[1] = dev->img_buffers[1];
DBG (DBG_proc, "Reading image data for page %d, finished\n", page);
return status;
}

Wyświetl plik

@ -0,0 +1,266 @@
/*
Copyright (C) 2008, Panasonic Russia Ltd.
*/
/* sane - Scanner Access Now Easy.
Panasonic KV-S1020C / KV-S1025C USB scanners.
*/
#ifndef __KVS1025_LOW_H
#define __KVS1025_LOW_H
#include "kvs1025_cmds.h"
#define VENDOR_ID 0x04DA
typedef enum
{
KV_S1020C = 0x1007,
KV_S1025C = 0x1006
} KV_MODEL_TYPE;
/* Store an integer in 2, 3 or 4 byte in a big-endian array. */
#define Ito16(val, buf) { \
((unsigned char *)buf)[0] = ((val) >> 8) & 0xff; \
((unsigned char *)buf)[1] = ((val) >> 0) & 0xff; \
}
#define Ito24(val, buf) { \
((unsigned char *)buf)[0] = ((val) >> 16) & 0xff; \
((unsigned char *)buf)[1] = ((val) >> 8) & 0xff; \
((unsigned char *)buf)[2] = ((val) >> 0) & 0xff; \
}
#define Ito32(val, buf) { \
((unsigned char *)buf)[0] = ((val) >> 24) & 0xff; \
((unsigned char *)buf)[1] = ((val) >> 16) & 0xff; \
((unsigned char *)buf)[2] = ((val) >> 8) & 0xff; \
((unsigned char *)buf)[3] = ((val) >> 0) & 0xff; \
}
/* 32 bits from an array to an integer (eg ntohl). */
#define B32TOI(buf) \
((((unsigned char *)buf)[0] << 24) | \
(((unsigned char *)buf)[1] << 16) | \
(((unsigned char *)buf)[2] << 8) | \
(((unsigned char *)buf)[3] << 0))
/* 24 bits from an array to an integer. */
#define B24TOI(buf) \
(((unsigned char *)buf)[0] << 16) | \
(((unsigned char *)buf)[1] << 8) | \
(((unsigned char *)buf)[2] << 0))
#define SCSI_FD int
#define SCSI_BUFFER_SIZE (0x40000-12)
typedef enum
{
KV_SCSI_BUS = 0x01,
KV_USB_BUS = 0x02
} KV_BUS_MODE;
typedef enum
{
SM_BINARY = 0x00,
SM_DITHER = 0x01,
SM_GRAYSCALE = 0x02,
SM_COLOR = 0x05
} KV_SCAN_MODE;
typedef struct
{
unsigned char data[16];
int len;
} CDB;
typedef struct
{
int width;
int height;
} KV_PAPER_SIZE;
/* remarked -- KV-S1020C / KV-S1025C supports ADF only
typedef enum
{
TRUPER_ADF = 0,
TRUPER_FLATBED = 1
} KV_SCAN_SOURCE;
*/
/* options */
typedef enum
{
OPT_NUM_OPTS = 0,
/* General options */
OPT_MODE_GROUP,
OPT_MODE, /* scanner modes */
OPT_RESOLUTION, /* X and Y resolution */
OPT_DUPLEX, /* Duplex mode */
OPT_SCAN_SOURCE, /* Scan source, fixed to ADF */
OPT_FEEDER_MODE, /* Feeder mode, fixed to Continous */
OPT_LONGPAPER, /* Long paper mode */
OPT_LENGTHCTL, /* Length control mode */
OPT_MANUALFEED, /* Manual feed mode */
OPT_FEED_TIMEOUT, /* Feed timeout */
OPT_DBLFEED, /* Double feed detection mode */
OPT_FIT_TO_PAGE, /* Scanner shrinks image to fit scanned page */
/* Geometry group */
OPT_GEOMETRY_GROUP,
OPT_PAPER_SIZE, /* Paper size */
OPT_LANDSCAPE, /* true if landscape; new for Truper 3200/3600 */
OPT_TL_X, /* upper left X */
OPT_TL_Y, /* upper left Y */
OPT_BR_X, /* bottom right X */
OPT_BR_Y, /* bottom right Y */
OPT_ENHANCEMENT_GROUP,
OPT_BRIGHTNESS, /* Brightness */
OPT_CONTRAST, /* Contrast */
OPT_AUTOMATIC_THRESHOLD, /* Binary threshold */
OPT_HALFTONE_PATTERN, /* Halftone pattern */
OPT_AUTOMATIC_SEPARATION, /* Automatic separation */
OPT_WHITE_LEVEL, /* White level */
OPT_NOISE_REDUCTION, /* Noise reduction */
OPT_IMAGE_EMPHASIS, /* Image emphasis */
OPT_GAMMA, /* Gamma */
OPT_LAMP, /* Lamp -- color drop out */
OPT_INVERSE, /* Inverse image */
OPT_MIRROR, /* Mirror image */
OPT_JPEG, /* JPEG Compression */
/* must come last: */
OPT_NUM_OPTIONS
} KV_OPTION;
typedef struct
{
int memory_size; /* in MB */
int min_resolution; /* in DPI */
int max_resolution; /* in DPI */
int step_resolution; /* in DPI */
int support_duplex; /* 1 if true */
int support_lamp; /* 1 if true */
int max_x_range; /* in mm */
int max_y_range; /* in mm */
} KV_SUPPORT_INFO;
typedef struct kv_scanner_dev
{
struct kv_scanner_dev *next;
SANE_Device sane;
/* Infos from inquiry. */
char scsi_type;
char scsi_type_str[32];
char scsi_vendor[12];
char scsi_product[20];
char scsi_version[8];
/* Bus info */
KV_BUS_MODE bus_mode;
struct usb_device *usb_fd;
usb_dev_handle *usb_handle;
char *scsi_device_name;
SCSI_FD scsi_fd;
KV_MODEL_TYPE model_type;
SANE_Parameters params[2];
/* SCSI handling */
SANE_Byte *buffer0;
SANE_Byte *buffer; /* buffer = buffer0 + 12 */
/* for USB bulk transfer, a 12 bytes container
is required for each block */
/* Scanning handling. */
int scanning; /* TRUE if a scan is running. */
int current_page; /* the current page number, 0 is page 1 */
int current_side; /* the current side */
int bytes_to_read[2]; /* bytes to read */
/* Support info */
KV_SUPPORT_INFO support_info;
SANE_Range x_range, y_range;
/* Options */
SANE_Option_Descriptor opt[OPT_NUM_OPTIONS];
Option_Value val[OPT_NUM_OPTIONS];
SANE_Bool option_set;
/* Image buffer */
SANE_Byte *img_buffers[2];
SANE_Byte *img_pt[2];
int img_size[2];
} KV_DEV, *PKV_DEV;
#define GET_OPT_VAL_W(dev, idx) ((dev)->val[idx].w)
#define GET_OPT_VAL_L(dev, idx, token) get_optval_list(dev, idx, \
go_##token##_list, go_##token##_val)
#define IS_DUPLEX(dev) GET_OPT_VAL_W(dev, OPT_DUPLEX)
/* Prototypes in kvs1025_opt.c */
int get_optval_list (const PKV_DEV dev, int idx,
const SANE_String_Const * str_list, const int *val_list);
KV_SCAN_MODE kv_get_mode (const PKV_DEV dev);
int kv_get_depth (KV_SCAN_MODE mode);
void kv_calc_paper_size (const PKV_DEV dev, int *w, int *h);
const SANE_Option_Descriptor *kv_get_option_descriptor (PKV_DEV dev,
SANE_Int option);
void kv_init_options (PKV_DEV dev);
SANE_Status kv_control_option (PKV_DEV dev, SANE_Int option,
SANE_Action action, void *val,
SANE_Int * info);
void hexdump (int level, const char *comment, unsigned char *p, int l);
void kv_set_window_data (PKV_DEV dev,
KV_SCAN_MODE scan_mode,
int side, unsigned char *windowdata);
/* Prototypes in kvs1025_low.c */
SANE_Status kv_enum_devices ();
void kv_get_devices_list (const SANE_Device *** devices_list);
void kv_exit ();
SANE_Status kv_open (PKV_DEV dev);
SANE_Bool kv_already_open (PKV_DEV dev);
SANE_Status kv_open_by_name (SANE_String_Const devicename,
SANE_Handle * handle);
void kv_close (PKV_DEV dev);
SANE_Status kv_send_command (PKV_DEV dev,
PKV_CMD_HEADER header,
PKV_CMD_RESPONSE response);
/* Commands */
SANE_Status CMD_test_unit_ready (PKV_DEV dev, SANE_Bool * ready);
SANE_Status CMD_read_support_info (PKV_DEV dev);
SANE_Status CMD_scan (PKV_DEV dev);
SANE_Status CMD_set_window (PKV_DEV dev, int side, PKV_CMD_RESPONSE rs);
SANE_Status CMD_reset_window (PKV_DEV dev);
SANE_Status CMD_get_buff_status (PKV_DEV dev, int *front_size,
int *back_size);
SANE_Status CMD_wait_buff_status (PKV_DEV dev, int *front_size,
int *back_size);
SANE_Status CMD_read_pic_elements (PKV_DEV dev, int page, int side,
int *width, int *height);
SANE_Status CMD_read_image (PKV_DEV dev, int page, int side,
unsigned char *buffer, int *psize,
KV_CMD_RESPONSE * rs);
SANE_Status CMD_wait_document_existanse (PKV_DEV dev);
SANE_Status CMD_get_document_existanse (PKV_DEV dev);
SANE_Status CMD_set_timeout (PKV_DEV dev, SANE_Word timeout);
SANE_Status CMD_request_sense (PKV_DEV dev);
/* Scan routines */
SANE_Status AllocateImageBuffer (PKV_DEV dev);
SANE_Status ReadImageDataSimplex (PKV_DEV dev, int page);
SANE_Status ReadImageDataDuplex (PKV_DEV dev, int page);
SANE_Status ReadImageData (PKV_DEV dev, int page);
#endif /* #ifndef __KVS1025_LOW_H */

1498
backend/kvs1025_opt.c 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,407 @@
/*
Copyright (C) 2008, Panasonic Russia Ltd.
*/
/* sane - Scanner Access Now Easy.
Panasonic KV-S1020C / KV-S1025C USB scanners.
*/
#define DEBUG_DECLARE_ONLY
#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 <sys/ioctl.h>
#include <usb.h>
#undef DIRECT_USB_IO
#ifdef DIRECT_USB_IO
#include <sys/time.h>
#endif
#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 "kvs1025_usb.h"
#include "kvs1025_cmds.h"
#include "../include/sane/sanei_debug.h"
extern PKV_DEV g_devices; /* Chain of devices */
extern const SANE_Device **g_devlist;
void usb_free_dev (struct usb_device *dev); /* Defined in libusb 0.1.12 */
void usb_free_bus (struct usb_bus *bus);
/* static functions */
/* Attach USB scanner */
static SANE_Status
attach_scanner_usb (struct usb_device *usb_fd)
{
PKV_DEV dev;
DBG (DBG_error, "attaching USB scanner %s\n", usb_fd->filename);
dev = (PKV_DEV) malloc (sizeof (KV_DEV));
if (dev == NULL)
return SANE_STATUS_NO_MEM;
memset (dev, 0, sizeof (KV_DEV));
dev->bus_mode = KV_USB_BUS;
dev->usb_fd = usb_fd;
dev->scsi_fd = -1;
dev->buffer0 = (unsigned char *) malloc (SCSI_BUFFER_SIZE + 12);
dev->buffer = dev->buffer0 + 12;
if (dev->buffer0 == NULL)
{
free (dev);
return SANE_STATUS_NO_MEM;
}
dev->scsi_type = 6;
strcpy (dev->scsi_type_str, "ADF Scanner");
strcpy (dev->scsi_vendor, "Panasonic");
strcpy (dev->scsi_product, usb_fd->descriptor.idProduct
== (int) KV_S1025C ? "KV-S1025C" : "KV-S1020C");
strcpy (dev->scsi_version, "1.00");
/* Set SANE_Device */
dev->sane.name = dev->usb_fd->filename;
dev->sane.vendor = dev->scsi_vendor;
dev->sane.model = dev->scsi_product;
dev->sane.type = dev->scsi_type_str;
/* Add into g_devices chain */
dev->next = g_devices;
g_devices = dev;
return SANE_STATUS_GOOD;
}
/* Get all supported scanners, and store into g_scanners_supported */
SANE_Status
kv_usb_enum_devices ()
{
struct usb_bus *bus;
struct usb_device *dev;
SANE_Status status;
int cnt = 0;
int i;
PKV_DEV pd;
DBG (DBG_proc, "kv_usb_enum_devices: enter\n");
/* Use libusb */
if (!usb_get_busses ())
{
usb_find_busses ();
usb_find_devices ();
}
for (bus = usb_get_busses (); bus; bus = bus->next)
{
for (dev = bus->devices; dev; dev = dev->next)
{
if (dev->config && dev->descriptor.idVendor == VENDOR_ID)
{
if (dev->descriptor.idProduct ==
(int) KV_S1025C
|| dev->descriptor.idProduct == (int) KV_S1020C)
{
status = attach_scanner_usb (dev);
if (status)
{
DBG (DBG_proc,
"kv_usb_enum_devices: leave on error "
" --out of memory\n");
return status;
}
else
{
cnt++;
}
}
}
}
}
g_devlist =
(const SANE_Device **) malloc (sizeof (SANE_Device *) * (cnt + 1));
if (g_devlist == NULL)
{
DBG (DBG_proc,
"kv_usb_enum_devices: leave on error " " --out of memory\n");
return SANE_STATUS_NO_MEM;
}
pd = g_devices;
for (i = 0; i < cnt; i++)
{
g_devlist[i] = (const SANE_Device *) &pd->sane;
pd = pd->next;
}
g_devlist[cnt] = 0;
DBG (DBG_proc, "kv_usb_enum_devices: leave with %d devices.\n", cnt);
return SANE_STATUS_GOOD;
}
/* Check if device is already open */
SANE_Bool
kv_usb_already_open (PKV_DEV dev)
{
return (dev->usb_handle != NULL);
}
/* Open an USB device */
SANE_Status
kv_usb_open (PKV_DEV dev)
{
DBG (DBG_proc, "kv_usb_open: enter\n");
if (dev->usb_handle)
{
DBG (DBG_proc, "kv_usb_open: leave -- already open\n");
return SANE_STATUS_GOOD;
}
dev->usb_handle = usb_open (dev->usb_fd);
if (!dev->usb_handle)
{
DBG (DBG_error, "kv_usb_open: leave -- cannot open device\n");
return SANE_STATUS_IO_ERROR;
}
/* Claim USB interface 0 */
if (usb_claim_interface (dev->usb_handle, 0) != 0)
{
DBG (DBG_error, "kv_usb_open: leave -- "
"cannot claim interface '0', " "check permission please.\n");
usb_close (dev->usb_handle);
dev->usb_handle = NULL;
return SANE_STATUS_ACCESS_DENIED;
}
usb_clear_halt (dev->usb_handle, (int) KV_CMD_IN);
usb_clear_halt (dev->usb_handle, (int) KV_CMD_OUT);
DBG (DBG_proc, "kv_usb_open: leave\n");
return SANE_STATUS_GOOD;
}
/* Close an USB device */
void
kv_usb_close (PKV_DEV dev)
{
DBG (DBG_proc, "kv_usb_close: enter\n");
if (dev->usb_handle)
{
usb_release_interface (dev->usb_handle, 0);
usb_close (dev->usb_handle);
dev->usb_handle = NULL;
}
DBG (DBG_proc, "kv_usb_close: leave\n");
}
/* Clean up the USB bus and release all resources allocated to devices */
void
kv_usb_cleanup ()
{
struct usb_bus *bus, *old_bus;
struct usb_device *dev, *old_dev;
bus = usb_get_busses ();
while (bus)
{
dev = bus->devices;
while (dev)
{
old_dev = dev;
dev = dev->next;
usb_free_dev (old_dev);
}
old_bus = bus;
bus = bus->next;
usb_free_bus (old_bus);
}
}
/* Send command via USB, and get response data */
SANE_Status
kv_usb_escape (usb_dev_handle * usb_handle,
PKV_CMD_HEADER header, unsigned char *status_byte)
{
int got_response = 0;
unsigned char cmd_buff[24];
memset (cmd_buff, 0, 24);
cmd_buff[3] = 0x18; /* container length */
cmd_buff[5] = 1; /* container type: command block */
cmd_buff[6] = 0x90; /* code */
if (usb_handle == NULL)
{
DBG (DBG_error, "kv_usb_escape: error, device not open.\n");
return SANE_STATUS_IO_ERROR;
}
memcpy (cmd_buff + 12, header->cdb, header->cdb_size);
/* Send command */
if (usb_bulk_write (usb_handle, (int) KV_CMD_OUT, (char *) cmd_buff,
24, KV_CMD_TIMEOUT) != 24)
{
DBG (DBG_error, "usb_bulk_write: Error writing command.\n");
hexdump (DBG_error, "cmd block", cmd_buff, 24);
return SANE_STATUS_IO_ERROR;
}
/* Send / Read data */
if (header->direction == KV_CMD_IN)
{
int size_read;
int size = header->data_size + 12;
unsigned char *data = ((unsigned char *) header->data) - 12;
size_read =
usb_bulk_read (usb_handle, (int) KV_CMD_IN,
(char *) data, size, KV_CMD_TIMEOUT);
if (size_read <= 0)
{
usb_clear_halt (usb_handle, (int) KV_CMD_IN);
usb_clear_halt (usb_handle, (int) KV_CMD_OUT);
DBG (DBG_error, "usb_bulk_read: Error reading data.\n");
return SANE_STATUS_IO_ERROR;
}
if (size_read != size)
{
DBG (DBG_shortread, "usb_bulk_read: Warning - short read\n");
DBG (DBG_shortread, "usb_bulk_read: bytes to read = %d\n", size);
DBG (DBG_shortread,
"usb_bulk_read: bytes actual read = %d\n", size_read);
/*hexdump (DBG_shortread, "data", data, size_read); */
}
}
if (header->direction == KV_CMD_OUT)
{
int size_written;
int size = header->data_size + 12;
unsigned char *data = ((unsigned char *) header->data) - 12;
memset (data, 0, 12);
Ito32 (size, data);
data[5] = 0x02; /* container type: data block */
data[6] = 0xb0; /* code */
size_written = usb_bulk_write (usb_handle, (int) KV_CMD_OUT,
(char *) data, size, KV_CMD_TIMEOUT);
if (size_written <= 0)
{
usb_clear_halt (usb_handle, (int) KV_CMD_IN);
usb_clear_halt (usb_handle, (int) KV_CMD_OUT);
}
if (size_written < 0)
{
DBG (DBG_error, "usb_bulk_write: Error writing data.\n");
return SANE_STATUS_IO_ERROR;
}
if (size_written != size)
{
DBG (DBG_shortread, "usb_bulk_write: Warning - short written\n");
DBG (DBG_shortread, "usb_bulk_write: bytes to write = %d\n", size);
DBG (DBG_shortread,
"usb_bulk_write: bytes actual written = %d\n", size_written);
hexdump (DBG_shortread, "data", data, size_written);
}
}
/* Get response */
if (!got_response)
{
int r;
if ((r = usb_bulk_read (usb_handle, (int) KV_CMD_IN, (char *) cmd_buff,
16, KV_CMD_TIMEOUT)) != 16)
{
DBG (DBG_error, "usb_bulk_read: Error reading response."
" read %d bytes\n", r);
usb_clear_halt (usb_handle, (int) KV_CMD_IN);
usb_clear_halt (usb_handle, (int) KV_CMD_OUT);
return SANE_STATUS_IO_ERROR;
}
}
if (cmd_buff[5] != 3)
{
DBG (DBG_error, "usb_bulk_read: Invalid response block.\n");
hexdump (DBG_error, "response", cmd_buff, 16);
return SANE_STATUS_IO_ERROR;
}
*status_byte = cmd_buff[15] & 0x3E;
return SANE_STATUS_GOOD;
}
/* Send command via USB, and request sense on CHECK CONDITION status */
SANE_Status
kv_usb_send_command (usb_dev_handle * usb_handle,
PKV_CMD_HEADER header, PKV_CMD_RESPONSE response)
{
unsigned char status = 0;
SANE_Status s;
memset (response, 0, sizeof (KV_CMD_RESPONSE));
response->status = KV_FAILED;
s = kv_usb_escape (usb_handle, header, &status);
if (s)
{
#ifndef DIRECT_USB_IO
status = 0x02;
#else
return s;
#endif
}
if (status == 0x02)
{ /* check condition */
/* request sense */
KV_CMD_HEADER hdr;
memset (&hdr, 0, sizeof (hdr));
hdr.direction = KV_CMD_IN;
hdr.cdb[0] = SCSI_REQUEST_SENSE;
hdr.cdb[4] = 0x12;
hdr.cdb_size = 6;
hdr.data_size = 0x12;
hdr.data = &response->sense;
if (kv_usb_escape (usb_handle, &hdr, &status) != 0)
return SANE_STATUS_IO_ERROR;
hexdump (DBG_error, "sense data", (unsigned char *) &response->sense,
0x12);
response->status = KV_CHK_CONDITION;
}
else
{
response->status = KV_SUCCESS;
}
return SANE_STATUS_GOOD;
}

Wyświetl plik

@ -0,0 +1,23 @@
/*
Copyright (C) 2008, Panasonic Russia Ltd.
*/
/* sane - Scanner Access Now Easy.
Panasonic KV-S1020C / KV-S1025C USB scanners.
*/
#ifndef __KVS1025_USB_H
#define __KVS1025_USB_H
#include "kvs1025_cmds.h"
SANE_Status kv_usb_enum_devices ();
SANE_Status kv_usb_open (PKV_DEV dev);
SANE_Bool kv_usb_already_open (PKV_DEV dev);
void kv_usb_close (PKV_DEV dev);
void kv_usb_cleanup ();
SANE_Status kv_usb_send_command (usb_dev_handle * usb_handle,
PKV_CMD_HEADER header,
PKV_CMD_RESPONSE response);
#endif /* #ifndef __KVS1025_USB_H */

Wyświetl plik

@ -0,0 +1,29 @@
;
; SANE Backend specification file
;
; It's basically emacs-lisp --- so ";" indicates comment to end of line.
; All syntactic elements are keyword tokens, followed by a string or
; keyword argument, as specified.
;
; ":backend" *must* be specified.
; All other information is optional (but what good is the file without it?).
;
:backend "kvs1025" ; name of backend
:version "1" ; version of backend
:manpage "sane-kvs1025" ; name of manpage (if it exists)
:comment "New backend for SANE release 1.0.21, see sane-kvs1025 manpage"
:devicetype :scanner ; start of a list of devices....
:mfg "Panasonic" ; name a manufacturer
:url "http://www.panasonic.com/"
:model "KV-S1020C"
:interface "USB"
:usbid "0x04da" "0x1007"
:status :good
:model "KV-S1025C"
:interface "USB"
:usbid "0x04da" "0x1006"
:status :good

Wyświetl plik

@ -0,0 +1,31 @@
.TH sane\-kvs1025 5 "12 Feb 2010" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy"
.IX sane\-kvs1025
.SH NAME
sane\-kvs1025 \- SANE backend for Panasonic KV-S102xC USB ADF scanners.
.SH DESCRIPTION
The
.B sane\-kvs1025
library implements a SANE (Scanner Access Now Easy) backend which
provides access to the Panasonic KV-S1020C and KV-S1025C scanners.
.SH KNOWN ISSUES
The backend uses libusb directly, instead of sanei_usb, so it will not
work on some platforms.
This document was written by the SANE project, which has no information
regarding the capabilites or reliability of the backend. All information
contained here is suspect.
.SH CREDITS
The backend was written by Panasonic Russia Ltd.
The backend was ported to sane-backends 1.0.21 by m. allan noah.
.SH "SEE ALSO"
sane(7), sane\-usb(5)
.SH AUTHOR
m. allan noah: <kitno455 a t gmail d o t com>