kopia lustrzana https://gitlab.com/sane-project/backends
972 wiersze
24 KiB
C
972 wiersze
24 KiB
C
/* sane - Scanner Access Now Easy.
|
|
|
|
Copyright (C) 2018 Stanislav Yuzvinsky
|
|
Based on the work done by viruxx
|
|
|
|
This file is part of the SANE package.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
MA 02111-1307, USA.
|
|
|
|
As a special exception, the authors of SANE give permission for
|
|
additional uses of the libraries contained in this release of SANE.
|
|
|
|
The exception is that, if you link a SANE library with other files
|
|
to produce an executable, this does not by itself cause the
|
|
resulting executable to be covered by the GNU General Public
|
|
License. Your use of that executable is in no way restricted on
|
|
account of linking the SANE library code into it.
|
|
|
|
This exception does not, however, invalidate any other reasons why
|
|
the executable file might be covered by the GNU General Public
|
|
License.
|
|
|
|
If you submit changes to SANE to the maintainers to be included in
|
|
a subsequent release, you agree by submitting the changes that
|
|
those changes may be distributed with this exception intact.
|
|
|
|
If you write modifications of your own for SANE, it is your choice
|
|
whether to permit this exception to apply to your modifications.
|
|
If you do not wish that, delete this exception notice.
|
|
*/
|
|
|
|
#include "../include/sane/config.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "../include/sane/sane.h"
|
|
#include "../include/sane/sanei.h"
|
|
#include "../include/sane/sanei_usb.h"
|
|
#include "../include/sane/saneopts.h"
|
|
#include "../include/sane/sanei_backend.h"
|
|
#include "../include/sane/sanei_debug.h"
|
|
|
|
#include "ricoh2_buffer.c"
|
|
|
|
#define MAX_OPTION_STRING_SIZE 255
|
|
#define MAX_LINE_SIZE 240 * 256 /* = 61440 */
|
|
#define HEIGHT_PIXELS_300DPI 3508
|
|
#define WIDTH_BYTES_300DPI 2560
|
|
#define WIDTH_PIXELS_300DPI 2550
|
|
#define INFO_SIZE (WIDTH_BYTES_300DPI - WIDTH_PIXELS_300DPI)
|
|
#define USB_TIMEOUT_MS 20000
|
|
#define MAX_COMMAND_SIZE 64
|
|
|
|
#define CHECK_IF(x) if (!(x)) return SANE_STATUS_INVAL
|
|
|
|
typedef enum
|
|
{
|
|
OPT_NUM_OPTS = 0,
|
|
OPT_MODE,
|
|
OPT_RESOLUTION,
|
|
|
|
/* must come last: */
|
|
NUM_OPTIONS
|
|
}
|
|
Ricoh_Options;
|
|
|
|
typedef enum
|
|
{
|
|
SCAN_MODE_COLOR,
|
|
SCAN_MODE_GRAY
|
|
}
|
|
Scan_Mode;
|
|
|
|
|
|
typedef struct Ricoh2_Device {
|
|
struct Ricoh2_Device *next;
|
|
SANE_Device sane;
|
|
SANE_Bool active;
|
|
|
|
/* options */
|
|
SANE_Option_Descriptor opt[NUM_OPTIONS];
|
|
Option_Value val[NUM_OPTIONS];
|
|
|
|
/* acquiring session */
|
|
SANE_Int dn;
|
|
SANE_Bool cancelled;
|
|
Scan_Mode mode;
|
|
SANE_Int resolution;
|
|
SANE_Bool eof;
|
|
size_t bytes_to_read;
|
|
ricoh2_buffer *buffer;
|
|
|
|
}
|
|
Ricoh2_Device;
|
|
|
|
typedef struct Ricoh2_device_info {
|
|
SANE_Int product_id;
|
|
SANE_String_Const device_name;
|
|
}
|
|
Ricoh2_device_info;
|
|
|
|
static Ricoh2_device_info supported_devices[] = {
|
|
{ 0x042c, "Aficio SP100SU" },
|
|
{ 0x0438, "Aficio SG3100SNw" },
|
|
{ 0x0448, "Aficio SP111SU" }
|
|
};
|
|
|
|
static SANE_String_Const mode_list[] = {
|
|
SANE_VALUE_SCAN_MODE_COLOR,
|
|
SANE_VALUE_SCAN_MODE_GRAY,
|
|
NULL
|
|
};
|
|
static SANE_String_Const default_mode = SANE_VALUE_SCAN_MODE_COLOR;
|
|
|
|
static SANE_Int resolution_list[] = {
|
|
2, 300, 600
|
|
};
|
|
static SANE_Int default_resolution = 300;
|
|
|
|
static SANE_Bool initialized = SANE_FALSE;
|
|
static Ricoh2_Device *ricoh2_devices = NULL;
|
|
static const SANE_Device **sane_devices = NULL;
|
|
static SANE_Int num_devices = 0;
|
|
|
|
static Ricoh2_Device *
|
|
lookup_handle(SANE_Handle handle)
|
|
{
|
|
Ricoh2_Device *device;
|
|
|
|
for (device = ricoh2_devices; device; device = device->next)
|
|
{
|
|
if (device == handle)
|
|
return device;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static SANE_String_Const get_model_by_productid(SANE_Int id)
|
|
{
|
|
size_t i = 0;
|
|
for (; i < sizeof (supported_devices) / sizeof (supported_devices[0]); ++i)
|
|
{
|
|
if (supported_devices[i].product_id == id)
|
|
{
|
|
return supported_devices[i].device_name;
|
|
}
|
|
}
|
|
|
|
return "Unidentified device";
|
|
}
|
|
|
|
static SANE_Status
|
|
attach (SANE_String_Const devname)
|
|
{
|
|
SANE_Int dn = -1;
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
Ricoh2_Device *device = NULL;
|
|
SANE_Int vendor, product;
|
|
|
|
for (device = ricoh2_devices; device; device = device->next)
|
|
{
|
|
if (strcmp (device->sane.name, devname) == 0)
|
|
{
|
|
device->active = SANE_TRUE;
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
}
|
|
|
|
device = (Ricoh2_Device *) malloc (sizeof (Ricoh2_Device));
|
|
if (!device)
|
|
{
|
|
return SANE_STATUS_NO_MEM;
|
|
}
|
|
|
|
DBG (8, "attach %s\n", devname);
|
|
status = sanei_usb_open (devname, &dn);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "attach: couldn't open device `%s': %s\n", devname,
|
|
sane_strstatus (status));
|
|
return status;
|
|
}
|
|
|
|
status = sanei_usb_get_vendor_product (dn, &vendor, &product);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1,
|
|
"attach: couldn't get vendor and product ids of device `%s': %s\n",
|
|
devname, sane_strstatus (status));
|
|
sanei_usb_close (dn);
|
|
return status;
|
|
}
|
|
|
|
sanei_usb_close (dn);
|
|
device->sane.name = strdup (devname);
|
|
device->sane.vendor = "Ricoh";
|
|
device->sane.model = get_model_by_productid (product);
|
|
device->sane.type = "flatbed scanner";
|
|
device->active = SANE_TRUE;
|
|
device->buffer = NULL;
|
|
|
|
device->next = ricoh2_devices;
|
|
ricoh2_devices = device;
|
|
|
|
DBG (2, "Found device %s\n", device->sane.name);
|
|
++num_devices;
|
|
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
static SANE_Status
|
|
init_options(Ricoh2_Device *dev)
|
|
{
|
|
SANE_Option_Descriptor *od;
|
|
|
|
DBG (8, "init_options: dev = %p\n", (void *) dev);
|
|
|
|
/* number of options */
|
|
od = &(dev->opt[OPT_NUM_OPTS]);
|
|
od->name = SANE_NAME_NUM_OPTIONS;
|
|
od->title = SANE_TITLE_NUM_OPTIONS;
|
|
od->desc = SANE_DESC_NUM_OPTIONS;
|
|
od->type = SANE_TYPE_INT;
|
|
od->unit = SANE_UNIT_NONE;
|
|
od->size = sizeof (SANE_Word);
|
|
od->cap = SANE_CAP_SOFT_DETECT;
|
|
od->constraint_type = SANE_CONSTRAINT_NONE;
|
|
od->constraint.range = 0;
|
|
dev->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
|
|
|
|
/* mode - sets the scan mode: Color, Gray */
|
|
od = &(dev->opt[OPT_MODE]);
|
|
od->name = SANE_NAME_SCAN_MODE;
|
|
od->title = SANE_TITLE_SCAN_MODE;
|
|
od->desc = SANE_DESC_SCAN_MODE;
|
|
od->type = SANE_TYPE_STRING;
|
|
od->unit = SANE_UNIT_NONE;
|
|
od->size = MAX_OPTION_STRING_SIZE;
|
|
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
|
|
od->constraint_type = SANE_CONSTRAINT_STRING_LIST;
|
|
od->constraint.string_list = mode_list;
|
|
dev->val[OPT_MODE].s = malloc (od->size);
|
|
if (!dev->val[OPT_MODE].s)
|
|
return SANE_STATUS_NO_MEM;
|
|
strcpy (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR);
|
|
|
|
/* resolution */
|
|
od = &(dev->opt[OPT_RESOLUTION]);
|
|
od->name = SANE_NAME_SCAN_RESOLUTION;
|
|
od->title = SANE_TITLE_SCAN_RESOLUTION;
|
|
od->desc = SANE_DESC_SCAN_RESOLUTION;
|
|
od->type = SANE_TYPE_INT;
|
|
od->unit = SANE_UNIT_DPI;
|
|
od->size = sizeof (SANE_Word);
|
|
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
|
|
od->constraint_type = SANE_CONSTRAINT_WORD_LIST;
|
|
od->constraint.word_list = resolution_list;
|
|
dev->val[OPT_RESOLUTION].w = 300;
|
|
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
SANE_Status
|
|
sane_init (SANE_Int *vc, SANE_Auth_Callback __sane_unused__ cb)
|
|
{
|
|
size_t i = 0;
|
|
|
|
DBG_INIT ();
|
|
|
|
DBG(8, ">sane_init\n");
|
|
|
|
sanei_usb_init ();
|
|
sanei_usb_set_timeout (USB_TIMEOUT_MS);
|
|
|
|
num_devices = 0;
|
|
|
|
for (; i < sizeof (supported_devices) / sizeof (supported_devices[0]); ++i)
|
|
{
|
|
sanei_usb_find_devices (0x5ca, supported_devices[i].product_id, attach);
|
|
}
|
|
|
|
if (vc)
|
|
*vc = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, 0);
|
|
DBG(8, "<sane_init\n");
|
|
|
|
initialized = SANE_TRUE;
|
|
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
SANE_Status
|
|
sane_get_devices (const SANE_Device ***dl,
|
|
SANE_Bool __sane_unused__ local)
|
|
{
|
|
Ricoh2_Device *device = NULL;
|
|
SANE_Int i = 0;
|
|
|
|
DBG(8, ">sane_get_devices\n");
|
|
|
|
num_devices = 0;
|
|
sanei_usb_find_devices (0x5ca, 0x042c, attach);
|
|
sanei_usb_find_devices (0x5ca, 0x0448, attach);
|
|
|
|
if (sane_devices)
|
|
free (sane_devices);
|
|
|
|
sane_devices = (const SANE_Device **) malloc (sizeof (const SANE_Device *)
|
|
* (num_devices + 1));
|
|
if (!sane_devices)
|
|
return SANE_STATUS_NO_MEM;
|
|
|
|
for (device = ricoh2_devices; device; device = device->next)
|
|
if (device->active)
|
|
{
|
|
sane_devices[i++] = &(device->sane);
|
|
}
|
|
|
|
sane_devices[i] = NULL;
|
|
*dl = sane_devices;
|
|
|
|
DBG(2, "found %i devices\n", i);
|
|
DBG(8, "<sane_get_devices\n");
|
|
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
SANE_Status
|
|
sane_open (SANE_String_Const name, SANE_Handle *handle)
|
|
{
|
|
Ricoh2_Device *device;
|
|
SANE_Status status;
|
|
|
|
DBG (8, ">sane_open: devicename=\"%s\", handle=%p\n", name,
|
|
(void *) handle);
|
|
|
|
CHECK_IF (initialized);
|
|
CHECK_IF (handle);
|
|
|
|
/* walk the linked list of scanner device until there is a match
|
|
* with the device name */
|
|
for (device = ricoh2_devices; device; device = device->next)
|
|
{
|
|
DBG (2, "sane_open: devname from list: %s\n",
|
|
device->sane.name);
|
|
if (strcmp (name, "") == 0
|
|
|| strcmp (name, "ricoh") == 0
|
|
|| strcmp (name, device->sane.name) == 0)
|
|
break;
|
|
}
|
|
|
|
*handle = device;
|
|
|
|
if (!device)
|
|
{
|
|
DBG (1, "sane_open: Not a Ricoh device\n");
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
|
|
status = init_options (device);
|
|
if (status != SANE_STATUS_GOOD)
|
|
return status;
|
|
|
|
DBG (8, "<sane_open\n");
|
|
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
const SANE_Option_Descriptor *
|
|
sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
|
|
{
|
|
Ricoh2_Device *device;
|
|
|
|
DBG (8, "<sane_get_option_descriptor: handle=%p, option = %d\n",
|
|
(void *) handle, option);
|
|
|
|
if (!initialized)
|
|
return NULL;
|
|
|
|
/* Check for valid option number */
|
|
if ((option < 0) || (option >= NUM_OPTIONS))
|
|
return NULL;
|
|
|
|
if (!(device = lookup_handle(handle)))
|
|
return NULL;
|
|
|
|
if (device->opt[option].name)
|
|
{
|
|
DBG (8, ">sane_get_option_descriptor: name=%s\n",
|
|
device->opt[option].name);
|
|
}
|
|
|
|
return &(device->opt[option]);
|
|
}
|
|
|
|
SANE_Status
|
|
sane_control_option (SANE_Handle handle,
|
|
SANE_Int option,
|
|
SANE_Action action,
|
|
void *value,
|
|
SANE_Word *info)
|
|
{
|
|
Ricoh2_Device *device;
|
|
SANE_Status status;
|
|
|
|
DBG (8,
|
|
">sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n",
|
|
(void *) handle, option, action, (void *) value, (void *) info);
|
|
|
|
CHECK_IF (initialized);
|
|
device = lookup_handle (handle);
|
|
CHECK_IF (device);
|
|
CHECK_IF (value);
|
|
CHECK_IF (option >= 0 && option < NUM_OPTIONS);
|
|
CHECK_IF (device->opt[option].type != SANE_TYPE_GROUP);
|
|
|
|
switch (action)
|
|
{
|
|
case SANE_ACTION_SET_AUTO:
|
|
CHECK_IF (SANE_OPTION_IS_SETTABLE (device->opt[option].cap));
|
|
CHECK_IF (device->opt[option].cap & SANE_CAP_AUTOMATIC);
|
|
|
|
switch (option)
|
|
{
|
|
case OPT_RESOLUTION:
|
|
DBG (2,
|
|
"Setting value to default value of '%d' for option '%s'\n",
|
|
default_resolution,
|
|
device->opt[option].name);
|
|
device->val[option].w = default_resolution;
|
|
break;
|
|
|
|
case OPT_MODE:
|
|
DBG (2,
|
|
"Setting value to default value of '%s' for option '%s'\n",
|
|
(SANE_String_Const) default_mode,
|
|
device->opt[option].name);
|
|
strcpy (device->val[option].s, default_mode);
|
|
break;
|
|
|
|
default:
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
break;
|
|
|
|
case SANE_ACTION_SET_VALUE:
|
|
CHECK_IF (SANE_OPTION_IS_SETTABLE (device->opt[option].cap));
|
|
|
|
if (device->opt[option].type == SANE_TYPE_BOOL)
|
|
{
|
|
SANE_Bool bool_value = *(SANE_Bool *) value;
|
|
CHECK_IF (bool_value == SANE_TRUE || bool_value == SANE_FALSE);
|
|
}
|
|
|
|
if (device->opt[option].constraint_type == SANE_CONSTRAINT_RANGE)
|
|
{
|
|
status = sanei_constrain_value (&(device->opt[option]), value, info);
|
|
CHECK_IF (status == SANE_STATUS_GOOD);
|
|
}
|
|
|
|
|
|
switch (option)
|
|
{
|
|
case OPT_RESOLUTION:
|
|
DBG (2,
|
|
"Setting value to '%d' for option '%s'\n",
|
|
*(SANE_Word *) value,
|
|
device->opt[option].name);
|
|
device->val[option].w = *(SANE_Word *) value;
|
|
break;
|
|
|
|
case OPT_MODE:
|
|
DBG (2,
|
|
"Setting value to '%s' for option '%s'\n",
|
|
(SANE_String_Const)value,
|
|
device->opt[option].name);
|
|
strcpy (device->val[option].s, value);
|
|
break;
|
|
|
|
default:
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
break;
|
|
|
|
case SANE_ACTION_GET_VALUE:
|
|
|
|
switch (option)
|
|
{
|
|
case OPT_NUM_OPTS:
|
|
case OPT_RESOLUTION:
|
|
*(SANE_Word *) value = device->val[option].w;
|
|
DBG (2, "Option value = %d (%s)\n", *(SANE_Word *) value,
|
|
device->opt[option].name);
|
|
break;
|
|
case OPT_MODE:
|
|
strcpy (value, device->val[option].s);
|
|
break;
|
|
default:
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
|
|
DBG (8, "<sane_control_option\n");
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
static void
|
|
update_scan_params (Ricoh2_Device *device)
|
|
{
|
|
/* Scan mode: color or grayscale */
|
|
if (strcmp(device->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0)
|
|
{
|
|
device->mode = SCAN_MODE_COLOR;
|
|
}
|
|
else
|
|
{
|
|
device->mode = SCAN_MODE_GRAY;
|
|
}
|
|
|
|
/* resolution: 300 or 600dpi */
|
|
device->resolution = device->val[OPT_RESOLUTION].w;
|
|
}
|
|
|
|
|
|
SANE_Status
|
|
sane_get_parameters (SANE_Handle handle, SANE_Parameters *params)
|
|
{
|
|
Ricoh2_Device *device;
|
|
|
|
DBG (8, "sane_get_parameters: handle=%p, params=%p\n", (void *) handle,
|
|
(void *) params);
|
|
|
|
CHECK_IF (initialized);
|
|
device = lookup_handle (handle);
|
|
CHECK_IF (device);
|
|
CHECK_IF (params);
|
|
|
|
update_scan_params (device);
|
|
|
|
params->format =
|
|
device->mode == SCAN_MODE_COLOR ? SANE_FRAME_RGB : SANE_FRAME_GRAY;
|
|
params->last_frame = SANE_TRUE;
|
|
|
|
params->pixels_per_line = WIDTH_PIXELS_300DPI;
|
|
params->bytes_per_line = params->pixels_per_line;
|
|
params->lines = HEIGHT_PIXELS_300DPI;
|
|
params->depth = 8;
|
|
|
|
if (device->resolution == 600)
|
|
{
|
|
params->bytes_per_line *= 2;
|
|
params->pixels_per_line *= 2;
|
|
params->lines *= 2;
|
|
}
|
|
|
|
if (device->mode == SCAN_MODE_COLOR)
|
|
{
|
|
params->bytes_per_line *= 3;
|
|
}
|
|
|
|
DBG (8, ">sane_get_parameters: format = %s bytes_per_line = %d "
|
|
"depth = %d "
|
|
"pixels_per_line = %d "
|
|
"lines = %d\n",
|
|
(params->format == SANE_FRAME_RGB ? "rgb" : "gray"),
|
|
params->bytes_per_line,
|
|
params->depth,
|
|
params->pixels_per_line,
|
|
params->lines);
|
|
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
SANE_Byte *send_buffer;
|
|
size_t to_send;
|
|
SANE_Byte *receive_buffer;
|
|
size_t to_receive;
|
|
}
|
|
Send_Receive_Pair;
|
|
|
|
static SANE_Status
|
|
send_receive (SANE_Int dn, Send_Receive_Pair *transfer)
|
|
{
|
|
SANE_Status status;
|
|
size_t io_size;
|
|
SANE_Byte send_buffer[MAX_COMMAND_SIZE];
|
|
|
|
assert(transfer->to_send <= MAX_COMMAND_SIZE);
|
|
|
|
memset(send_buffer, 0, MAX_COMMAND_SIZE);
|
|
|
|
/* send a command */
|
|
io_size = MAX_COMMAND_SIZE;
|
|
DBG (128, "sending a packet of size %lu\n", io_size);
|
|
memcpy (send_buffer, transfer->send_buffer, transfer->to_send);
|
|
status = sanei_usb_write_bulk (dn, send_buffer, &io_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "could not send packet: %s\n", sane_strstatus (status));
|
|
return status;
|
|
}
|
|
|
|
/* receive a result */
|
|
io_size = transfer->to_receive;
|
|
DBG (128, "receiving a packet of size %lu\n", io_size);
|
|
if (io_size)
|
|
{
|
|
status = sanei_usb_read_bulk (dn, transfer->receive_buffer, &io_size);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "could not get a response for packet: %s\n",
|
|
sane_strstatus (status));
|
|
return status;
|
|
}
|
|
if (io_size != transfer->to_receive)
|
|
{
|
|
DBG (1, "unexpected size of received packet: expected %lu, "
|
|
"received %lu\n", transfer->to_receive, io_size);
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
}
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
static SANE_Status
|
|
init_scan(SANE_Int dn, Scan_Mode mode, SANE_Int resolution)
|
|
{
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
SANE_Byte dummy_buffer[11]; /* the longest expected reply */
|
|
size_t i;
|
|
|
|
SANE_Byte urb_init[] = { 0x03, 0x09, 0x01 };
|
|
SANE_Byte magic0[] = { 0x03, 0x0d, 0x0b };
|
|
SANE_Byte magic1[] = {
|
|
0x03, 0x0c, 0x11, 0x00, 0x00, 0x00, 0x01, 0x02, 0x05,
|
|
0xff, 0x00, 0x00, 0x00, 0x00, 0xec, 0x13, 0x6c, 0x1b };
|
|
SANE_Byte magic2[] = { 0x03, 0x0b, 0x08 };
|
|
SANE_Byte magic3[] = {
|
|
0x03, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x50, 0x6d, 0x06, 0x01 };
|
|
|
|
Send_Receive_Pair transfer[] =
|
|
{
|
|
{ urb_init, sizeof (urb_init), dummy_buffer, 1 },
|
|
{ magic0, sizeof (magic0), dummy_buffer, 11 },
|
|
{ magic1, sizeof (magic1), dummy_buffer, 0 },
|
|
{ magic2, sizeof (magic2), dummy_buffer, 8 },
|
|
{ magic3, sizeof (magic3), dummy_buffer, 0 }
|
|
};
|
|
|
|
if (resolution == 600)
|
|
magic1[6] = 0x02;
|
|
|
|
if (mode == SCAN_MODE_COLOR)
|
|
magic1[7] = 0x03;
|
|
|
|
for (i = 0;
|
|
i < sizeof (transfer) / sizeof (transfer[0])
|
|
&& (status == SANE_STATUS_GOOD);
|
|
++i)
|
|
{
|
|
DBG (128, "sending initialization packet %zi\n", i);
|
|
status = send_receive (dn, transfer + i);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
void
|
|
teardown_scan(SANE_Int dn)
|
|
{
|
|
SANE_Byte cancel_command[] = { 0x03, 0x0a };
|
|
SANE_Byte end_command[] = { 0x03, 0x09, 0x01 };
|
|
SANE_Byte dummy_buffer;
|
|
Send_Receive_Pair transfer;
|
|
|
|
DBG (128, "Sending cancel command\n");
|
|
transfer.send_buffer = cancel_command;
|
|
transfer.to_send = sizeof (cancel_command);
|
|
transfer.receive_buffer = &dummy_buffer;
|
|
transfer.to_receive = 0;
|
|
send_receive (dn, &transfer);
|
|
|
|
transfer.send_buffer = end_command;
|
|
transfer.to_send = sizeof (end_command);
|
|
transfer.receive_buffer = &dummy_buffer;
|
|
transfer.to_receive = 1;
|
|
send_receive (dn, &transfer);
|
|
}
|
|
|
|
SANE_Status
|
|
sane_start (SANE_Handle handle)
|
|
{
|
|
Ricoh2_Device *device;
|
|
SANE_Status status;
|
|
SANE_Int pixels_per_line;
|
|
SANE_Int resolution_factor = 1;
|
|
|
|
DBG (8, ">sane_start: handle=%p\n", (void *) handle);
|
|
|
|
CHECK_IF (initialized);
|
|
device = lookup_handle (handle);
|
|
CHECK_IF (device);
|
|
|
|
update_scan_params (device);
|
|
device->cancelled = SANE_FALSE;
|
|
|
|
status = sanei_usb_open (device->sane.name, &(device->dn));
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "could not open device %s: %s\n",
|
|
device->sane.name, sane_strstatus (status));
|
|
return status;
|
|
}
|
|
|
|
DBG (2, "usb device %s opened, device number is %d\n",
|
|
device->sane.name, device->dn);
|
|
|
|
status = sanei_usb_claim_interface (device->dn, 0);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "could not claim interface 0: %s\n",
|
|
sane_strstatus (status));
|
|
sanei_usb_close (device->dn);
|
|
return status;
|
|
}
|
|
|
|
sanei_usb_set_endpoint (device->dn,
|
|
USB_DIR_OUT | USB_ENDPOINT_TYPE_BULK,
|
|
0x03);
|
|
|
|
sanei_usb_set_endpoint (device->dn,
|
|
USB_DIR_IN | USB_ENDPOINT_TYPE_BULK,
|
|
0x85);
|
|
|
|
status = sanei_usb_reset (device->dn);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
DBG (1, "could not reset device %s: %s\n",
|
|
device->sane.name, sane_strstatus (status));
|
|
sanei_usb_close (device->dn);
|
|
return status;
|
|
}
|
|
|
|
|
|
status = init_scan (device->dn, device->mode, device->resolution);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
sanei_usb_close (device->dn);
|
|
return status;
|
|
}
|
|
|
|
resolution_factor = device->resolution == 600 ? 2 : 1;
|
|
|
|
pixels_per_line = WIDTH_PIXELS_300DPI * resolution_factor;
|
|
|
|
device->bytes_to_read =
|
|
WIDTH_PIXELS_300DPI * resolution_factor
|
|
* HEIGHT_PIXELS_300DPI * resolution_factor
|
|
* (device->mode == SCAN_MODE_COLOR ? 3 : 1);
|
|
|
|
device->buffer =
|
|
ricoh2_buffer_create (MAX_LINE_SIZE,
|
|
pixels_per_line,
|
|
INFO_SIZE * resolution_factor,
|
|
device->mode == SCAN_MODE_COLOR);
|
|
|
|
DBG (8, "<sane_start: %lu bytes to read\n", device->bytes_to_read);
|
|
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
SANE_Status
|
|
sane_read (SANE_Handle handle,
|
|
SANE_Byte *data,
|
|
SANE_Int maxlen,
|
|
SANE_Int *length)
|
|
{
|
|
SANE_Byte read_next_command[] = { 0x03, 0x0E, 0x04, 0, 0, 0, 0, 240 };
|
|
|
|
Ricoh2_Device *device;
|
|
SANE_Status status;
|
|
Send_Receive_Pair transfer;
|
|
|
|
DBG (16, ">sane_read: handle=%p, data=%p, maxlen = %d, length=%p\n",
|
|
(void *) handle, (void *) data, maxlen, (void *) length);
|
|
|
|
CHECK_IF (initialized);
|
|
device = lookup_handle (handle);
|
|
CHECK_IF (device);
|
|
CHECK_IF (length);
|
|
CHECK_IF (maxlen);
|
|
|
|
/*
|
|
EOF has already been reached before or acquisition process hasn't
|
|
been initiated at all
|
|
*/
|
|
if (device->bytes_to_read <= 0)
|
|
{
|
|
return SANE_STATUS_EOF;
|
|
}
|
|
|
|
if (!ricoh2_buffer_get_bytes_remain (device->buffer))
|
|
{
|
|
transfer.send_buffer = read_next_command;
|
|
transfer.to_send = sizeof (read_next_command);
|
|
transfer.receive_buffer =
|
|
ricoh2_buffer_get_internal_buffer (device->buffer);
|
|
transfer.to_receive = MAX_LINE_SIZE;
|
|
read_next_command[7] = transfer.to_receive / 256;
|
|
|
|
DBG (128, "Receiving data of size %zi\n", transfer.to_receive);
|
|
|
|
status = send_receive (device->dn, &transfer);
|
|
if (status != SANE_STATUS_GOOD)
|
|
{
|
|
device->bytes_to_read = 0;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
*length = ricoh2_buffer_get_data (device->buffer,
|
|
data,
|
|
min(maxlen, device->bytes_to_read));
|
|
|
|
device->bytes_to_read -= *length;
|
|
|
|
DBG (128,
|
|
"Read length %d, left to read %lu\n",
|
|
*length,
|
|
device->bytes_to_read);
|
|
|
|
DBG (128,
|
|
"%d bytes remain in the buffer\n",
|
|
ricoh2_buffer_get_bytes_remain(device->buffer));
|
|
|
|
/* we've just reached expected data size */
|
|
if (device->bytes_to_read <= 0)
|
|
{
|
|
ricoh2_buffer_dispose(device->buffer);
|
|
device->buffer = NULL;
|
|
return SANE_STATUS_EOF;
|
|
}
|
|
|
|
DBG (16, "<sane_read\n");
|
|
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
SANE_Status
|
|
sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
|
|
{
|
|
Ricoh2_Device *device;
|
|
DBG (8, "sane_set_io_mode: handle = %p, non_blocking = %d\n",
|
|
(void *) handle, non_blocking);
|
|
|
|
CHECK_IF (initialized);
|
|
device = lookup_handle (handle);
|
|
CHECK_IF (device);
|
|
|
|
if (non_blocking)
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
SANE_Status
|
|
sane_get_select_fd (SANE_Handle handle, SANE_Int *fd)
|
|
{
|
|
Ricoh2_Device *device;
|
|
DBG (8, "sane_get_select_fd: handle = %p, fd %s 0\n", (void *) handle,
|
|
fd ? "!=" : "=");
|
|
|
|
CHECK_IF (initialized);
|
|
device = lookup_handle (handle);
|
|
CHECK_IF (device);
|
|
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
void
|
|
sane_cancel (SANE_Handle handle)
|
|
{
|
|
Ricoh2_Device *device;
|
|
|
|
DBG (8, ">sane_cancel: handle = %p\n", (void *) handle);
|
|
|
|
if (!initialized)
|
|
return;
|
|
|
|
if (!(device = lookup_handle (handle)))
|
|
return;
|
|
|
|
if (device->cancelled)
|
|
return;
|
|
|
|
device->cancelled = SANE_TRUE;
|
|
|
|
teardown_scan (device->dn);
|
|
if (device->buffer)
|
|
{
|
|
ricoh2_buffer_dispose (device->buffer);
|
|
device->buffer = NULL;
|
|
}
|
|
|
|
sanei_usb_close(device->dn);
|
|
|
|
DBG (8, "<sane_cancel\n");
|
|
}
|
|
|
|
void
|
|
sane_close (SANE_Handle handle)
|
|
{
|
|
Ricoh2_Device *device;
|
|
|
|
DBG (8, ">sane_close\n");
|
|
|
|
if (!initialized)
|
|
return;
|
|
|
|
device = lookup_handle (handle);
|
|
if (!device)
|
|
return;
|
|
|
|
/* noop */
|
|
|
|
DBG (8, "<sane_close\n");
|
|
}
|
|
|
|
void
|
|
sane_exit (void)
|
|
{
|
|
Ricoh2_Device *device, *next;
|
|
|
|
DBG (8, ">sane_exit\n");
|
|
|
|
if (!initialized)
|
|
return;
|
|
|
|
for (device = ricoh2_devices, next = device; device; device = next)
|
|
{
|
|
next = device->next;
|
|
free (device);
|
|
}
|
|
|
|
if (sane_devices)
|
|
free (sane_devices);
|
|
|
|
sanei_usb_exit ();
|
|
initialized = SANE_FALSE;
|
|
|
|
DBG (8, "<sane_exit\n");
|
|
}
|