kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			404 wiersze
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			404 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");
 | |
| 			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 = 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);
 | |
| }
 |