/* * 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 * * 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 #include #include #include #include #include "epson2.h" #include "epson2-io.h" #include #include #include #include #include "epson2_scsi.h" #include "epson_usb.h" #include "epson2_net.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"); return SANE_STATUS_INVAL; } 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 = 0; DBG(15, "%s: size = %d, buf = %p\n", __func__, buf_size, buf); 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) { n = sanei_epson2_scsi_read(s->fd, buf, buf_size, status); } else if (s->hw->connection == SANE_EPSON_PIO) { 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 */ n = buf_size; /* buf_size gets overwritten */ *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\n", __func__, (u_long) buf_size, (long) n); *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; 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; } e2_recv(s, rxbuf, rxlen, &status); if (status != SANE_STATUS_GOOD) { DBG(1, "%s: rx err, %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 = %d\n", __func__, 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: %d\n", __func__, *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 = %d, buf = %p\n", __func__, params_len, 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 %d, got %d\n", __func__, reply_len, 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; }