kopia lustrzana https://gitlab.com/sane-project/backends
Adding new files for new kvs1025 backend
rodzic
07cd144f72
commit
5d12e39b7c
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
usb "Panasonic KV-S1025C"
|
||||
/dev/scanner
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
Plik diff jest za duży
Load Diff
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
|
@ -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>
|
||||
|
Ładowanie…
Reference in New Issue