sane-project-backends/backend/epson2-io.c

405 wiersze
9.3 KiB
C

/*
* I/O routines for Epson scanners
*
* Based on Kazuhiro Sasayama previous
* Work on epson.[ch] file from the SANE package.
* Please see those files for original copyrights.
*
* Copyright (C) 2006 Tower Technologies
* Author: Alessandro Zummo <a.zummo@towertech.it>
*
* 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, version 2.
*/
#define DEBUG_DECLARE_ONLY
#include "sane/config.h"
#include <ctype.h>
#include "epson2.h"
#include "epson2-io.h"
#include "sane/sanei_scsi.h"
#include "sane/sanei_usb.h"
#include "sane/sanei_pio.h"
#include "sane/sanei_tcp.h"
#include "epson2_scsi.h"
#include "epson_usb.h"
#include "epson2_net.h"
#include "byteorder.h"
/* flaming hack to get USB scanners
* working without timeouts under linux
* (cribbed from fujitsu.c)
*/
unsigned int r_cmd_count = 0;
unsigned int w_cmd_count = 0;
int
e2_send(Epson_Scanner * s, void *buf, size_t buf_size, size_t reply_len,
SANE_Status * status)
{
DBG(15, "%s: size = %lu, reply = %lu\n",
__func__, (u_long) buf_size, (u_long) reply_len);
if (buf_size == 2) {
char *cmd = buf;
switch (cmd[0]) {
case ESC:
DBG(9, "%s: ESC %c\n", __func__, cmd[1]);
break;
case FS:
DBG(9, "%s: FS %c\n", __func__, cmd[1]);
break;
}
}
if (DBG_LEVEL >= 125) {
unsigned int k;
const unsigned char *s = buf;
for (k = 0; k < buf_size; k++) {
DBG(125, "buf[%d] %02x %c\n", k, s[k],
isprint(s[k]) ? s[k] : '.');
}
}
if (s->hw->connection == SANE_EPSON_NET) {
if (reply_len == 0) {
DBG(0,
"Cannot send this command to a networked scanner\n");
*status = SANE_STATUS_INVAL;
return 0; /* nothing actually sent */
}
return sanei_epson_net_write(s, 0x2000, buf, buf_size,
reply_len, status);
} else if (s->hw->connection == SANE_EPSON_SCSI) {
return sanei_epson2_scsi_write(s->fd, buf, buf_size, status);
} else if (s->hw->connection == SANE_EPSON_PIO) {
size_t n;
if (buf_size == (n = sanei_pio_write(s->fd, buf, buf_size)))
*status = SANE_STATUS_GOOD;
else
*status = SANE_STATUS_INVAL;
return n;
} else if (s->hw->connection == SANE_EPSON_USB) {
size_t n;
n = buf_size;
*status = sanei_usb_write_bulk(s->fd, buf, &n);
w_cmd_count++;
DBG(20, "%s: cmd count, r = %d, w = %d\n",
__func__, r_cmd_count, w_cmd_count);
return n;
}
*status = SANE_STATUS_INVAL;
return 0;
/* never reached */
}
ssize_t
e2_recv(Epson_Scanner *s, void *buf, ssize_t buf_size,
SANE_Status *status)
{
ssize_t n = buf_size; /* network interface needs to read header back even data is 0.*/
DBG(15, "%s: size = %ld, buf = %p\n", __func__, (long) buf_size, buf);
*status = SANE_STATUS_GOOD;
if (s->hw->connection == SANE_EPSON_NET) {
n = sanei_epson_net_read(s, buf, buf_size, status);
} else if (s->hw->connection == SANE_EPSON_SCSI) {
if (buf_size)
n = sanei_epson2_scsi_read(s->fd, buf, buf_size, status);
} else if (s->hw->connection == SANE_EPSON_PIO) {
if (buf_size) {
if (buf_size ==
(n = sanei_pio_read(s->fd, buf, (size_t) buf_size)))
*status = SANE_STATUS_GOOD;
else
*status = SANE_STATUS_INVAL;
}
} else if (s->hw->connection == SANE_EPSON_USB) {
/* !!! only report an error if we don't read anything */
if (n) {
*status =
sanei_usb_read_bulk(s->fd, (SANE_Byte *) buf,
(size_t *) & n);
r_cmd_count += (n + 63) / 64; /* add # of packets, rounding up */
DBG(20, "%s: cmd count, r = %d, w = %d\n",
__func__, r_cmd_count, w_cmd_count);
if (n > 0)
*status = SANE_STATUS_GOOD;
}
}
if (n < buf_size) {
DBG(1, "%s: expected = %lu, got = %ld, canceling: %d\n", __func__,
(u_long) buf_size, (long) n, s->canceling);
*status = SANE_STATUS_IO_ERROR;
}
/* dump buffer if appropriate */
if (DBG_LEVEL >= 127 && n > 0) {
int k;
const unsigned char *s = buf;
for (k = 0; k < n; k++)
DBG(127, "buf[%d] %02x %c\n", k, s[k],
isprint(s[k]) ? s[k] : '.');
}
return n;
}
/* Simple function to exchange a fixed amount of
* data with the scanner
*/
SANE_Status
e2_txrx(Epson_Scanner * s, unsigned char *txbuf, size_t txlen,
unsigned char *rxbuf, size_t rxlen)
{
SANE_Status status;
size_t done;
done = e2_send(s, txbuf, txlen, rxlen, &status);
if (status != SANE_STATUS_GOOD) {
DBG(1, "%s: tx err, %s\n", __func__, sane_strstatus(status));
return status;
}
if (done != txlen) {
DBG(1, "%s: tx err, short write\n", __func__);
return SANE_STATUS_IO_ERROR;
}
e2_recv(s, rxbuf, rxlen, &status);
if (status != SANE_STATUS_GOOD) {
DBG(1, "%s: rx err, %s\n", __func__, sane_strstatus(status));
}
DBG(1, "%s: eds_recv status, %s\n", __func__, sane_strstatus(status));
return status;
}
/* This function should be used to send codes that only requires the scanner
* to give back an ACK or a NAK.
*/
SANE_Status
e2_cmd_simple(Epson_Scanner * s, void *buf, size_t buf_size)
{
unsigned char result;
SANE_Status status;
DBG(12, "%s: size = %lu\n", __func__, (u_long) buf_size);
status = e2_txrx(s, buf, buf_size, &result, 1);
if (status != SANE_STATUS_GOOD) {
DBG(1, "%s: failed, %s\n", __func__, sane_strstatus(status));
return status;
}
if (result == ACK)
return SANE_STATUS_GOOD;
if (result == NAK) {
DBG(3, "%s: NAK\n", __func__);
return SANE_STATUS_INVAL;
}
DBG(1, "%s: result is neither ACK nor NAK but 0x%02x\n", __func__,
result);
return SANE_STATUS_GOOD;
}
/* receives a 4 or 6 bytes information block from the scanner*/
SANE_Status
e2_recv_info_block(Epson_Scanner * s, unsigned char *scanner_status,
size_t info_size, size_t * payload_size)
{
SANE_Status status;
unsigned char info[6];
if (s->hw->connection == SANE_EPSON_PIO)
e2_recv(s, info, 1, &status);
else
e2_recv(s, info, info_size, &status);
if (status != SANE_STATUS_GOOD)
return status;
/* check for explicit NAK */
if (info[0] == NAK) {
DBG(1, "%s: command not supported\n", __func__);
return SANE_STATUS_UNSUPPORTED;
}
/* check the first byte: if it's not STX, bail out */
if (info[0] != STX) {
DBG(1, "%s: expecting STX, got %02X\n", __func__, info[0]);
return SANE_STATUS_INVAL;
}
/* if connection is PIO read the remaining bytes. */
if (s->hw->connection == SANE_EPSON_PIO) {
e2_recv(s, &info[1], info_size - 1, &status);
if (status != SANE_STATUS_GOOD)
return status;
}
if (scanner_status)
*scanner_status = info[1];
if (payload_size) {
*payload_size = le16atoh(&info[2]);
if (info_size == 6)
*payload_size *= le16atoh(&info[4]);
DBG(14, "%s: payload length: %lu\n", __func__,
(u_long) *payload_size);
}
return SANE_STATUS_GOOD;
}
/* This function can be called for commands that
* will be answered by the scanner with an info block of 4 bytes
* and a variable payload. The payload is passed back to the caller
* in **buf. The caller must free it if != NULL,
* even if the status != SANE_STATUS_GOOD.
*/
SANE_Status
e2_cmd_info_block(SANE_Handle handle, unsigned char *params,
unsigned char params_len, size_t reply_len,
unsigned char **buf, size_t * buf_len)
{
SANE_Status status;
Epson_Scanner *s = (Epson_Scanner *) handle;
size_t len;
DBG(13, "%s, params len = %d, reply len = %lu, buf = %p\n",
__func__, params_len, (u_long) reply_len, (void *) buf);
if (buf == NULL)
return SANE_STATUS_INVAL;
/* initialize */
*buf = NULL;
/* send command, we expect the info block + reply_len back */
e2_send(s, params, params_len,
reply_len ? reply_len + 4 : 0, &status);
if (status != SANE_STATUS_GOOD)
goto end;
status = e2_recv_info_block(s, NULL, 4, &len);
if (status != SANE_STATUS_GOOD)
goto end;
/* do we need to provide the length of the payload? */
if (buf_len)
*buf_len = len;
/* no payload, stop here */
if (len == 0)
goto end;
/* if a reply_len has been specified and the actual
* length differs, throw a warning
*/
if (reply_len && (len != reply_len)) {
DBG(1, "%s: mismatched len - expected %lu, got %lu\n",
__func__, (u_long) reply_len, (u_long) len);
}
/* allocate and receive the payload */
*buf = malloc(len);
if (*buf) {
memset(*buf, 0x00, len);
e2_recv(s, *buf, len, &status); /* receive actual data */
} else
status = SANE_STATUS_NO_MEM;
end:
if (status != SANE_STATUS_GOOD) {
DBG(1, "%s: failed, %s\n", __func__, sane_strstatus(status));
if (*buf) {
free(*buf);
*buf = NULL;
}
}
return status;
}
/* This is used for ESC commands with a single byte parameter. Scanner
* will answer with ACK/NAK.
*/
SANE_Status
e2_esc_cmd(Epson_Scanner * s, unsigned char cmd, unsigned char val)
{
SANE_Status status;
unsigned char params[2];
DBG(8, "%s: cmd = 0x%02x, val = %d\n", __func__, cmd, val);
if (!cmd)
return SANE_STATUS_UNSUPPORTED;
params[0] = ESC;
params[1] = cmd;
status = e2_cmd_simple(s, params, 2);
if (status != SANE_STATUS_GOOD)
return status;
params[0] = val;
return e2_cmd_simple(s, params, 1);
}
/* Send an ACK to the scanner */
SANE_Status
e2_ack(Epson_Scanner * s)
{
SANE_Status status;
e2_send(s, S_ACK, 1, 0, &status);
return status;
}
SANE_Status
e2_ack_next(Epson_Scanner * s, size_t reply_len)
{
SANE_Status status;
e2_send(s, S_ACK, 1, reply_len, &status);
return status;
}
SANE_Status
e2_cancel(Epson_Scanner * s)
{
DBG(1, "%s\n", __func__);
return e2_cmd_simple(s, S_CAN, 1);
}