kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			1092 wiersze
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			1092 wiersze
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
| /*
 | |
|  * ESC/I commands 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 <byteorder.h>
 | |
| #include <math.h>
 | |
| #include <sys/types.h>
 | |
| 
 | |
| #include "epson2.h"
 | |
| #include "epson2-io.h"
 | |
| #include "epson2-commands.h"
 | |
| 
 | |
| 
 | |
| /* ESC H, set zoom */
 | |
| SANE_Status
 | |
| esci_set_zoom(Epson_Scanner * s, unsigned char x, unsigned char y)
 | |
| {
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[2];
 | |
| 
 | |
| 	DBG(8, "%s: x = %d, y = %d\n", __func__, x, y);
 | |
| 
 | |
| 	if (!s->hw->cmd->set_zoom) {
 | |
| 		DBG(1, "%s: not supported\n", __func__);
 | |
| 		return SANE_STATUS_GOOD;
 | |
| 	}
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->set_zoom;
 | |
| 
 | |
| 	status = e2_cmd_simple(s, params, 2);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	params[0] = x;
 | |
| 	params[1] = y;
 | |
| 
 | |
| 	return e2_cmd_simple(s, params, 2);
 | |
| }
 | |
| 
 | |
| /* ESC R */
 | |
| SANE_Status
 | |
| esci_set_resolution(Epson_Scanner * s, int x, int y)
 | |
| {
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[4];
 | |
| 
 | |
| 	DBG(8, "%s: x = %d, y = %d\n", __func__, x, y);
 | |
| 
 | |
| 	if (!s->hw->cmd->set_resolution) {
 | |
| 		DBG(1, "%s: not supported\n", __func__);
 | |
| 		return SANE_STATUS_GOOD;
 | |
| 	}
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->set_resolution;
 | |
| 
 | |
| 	status = e2_cmd_simple(s, params, 2);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	params[0] = x;
 | |
| 	params[1] = x >> 8;
 | |
| 	params[2] = y;
 | |
| 	params[3] = y >> 8;
 | |
| 
 | |
| 	return e2_cmd_simple(s, params, 4);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Sends the "set scan area" command to the scanner with the currently selected
 | |
|  * scan area. This scan area must be already corrected for "color shuffling" if
 | |
|  * necessary.
 | |
|  */
 | |
| 
 | |
| SANE_Status
 | |
| esci_set_scan_area(Epson_Scanner * s, int x, int y, int width, int height)
 | |
| {
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[8];
 | |
| 
 | |
| 	DBG(8, "%s: x = %d, y = %d, w = %d, h = %d\n",
 | |
| 	    __func__, x, y, width, height);
 | |
| 
 | |
| 	if (!s->hw->cmd->set_scan_area) {
 | |
| 		DBG(1, "%s: not supported\n", __func__);
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 	}
 | |
| 
 | |
| 	/* verify the scan area */
 | |
| 	if (x < 0 || y < 0 || width <= 0 || height <= 0)
 | |
| 		return SANE_STATUS_INVAL;
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->set_scan_area;
 | |
| 
 | |
| 	status = e2_cmd_simple(s, params, 2);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	params[0] = x;
 | |
| 	params[1] = x >> 8;
 | |
| 	params[2] = y;
 | |
| 	params[3] = y >> 8;
 | |
| 	params[4] = width;
 | |
| 	params[5] = width >> 8;
 | |
| 	params[6] = height;
 | |
| 	params[7] = height >> 8;
 | |
| 
 | |
| 	return e2_cmd_simple(s, params, 8);
 | |
| }
 | |
| 
 | |
| static int
 | |
| get_roundup_index(double frac[], int n)
 | |
| {
 | |
| 	int i, index = -1;
 | |
| 	double max_val = 0.0;
 | |
| 
 | |
| 	for (i = 0; i < n; i++) {
 | |
| 
 | |
| 		if (frac[i] < 0)
 | |
| 			continue;
 | |
| 
 | |
| 		if (max_val < frac[i]) {
 | |
| 			index = i;
 | |
| 			max_val = frac[i];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return index;
 | |
| }
 | |
| 
 | |
| static int
 | |
| get_rounddown_index(double frac[], int n)
 | |
| {
 | |
| 	int i, index = -1;
 | |
| 	double min_val = 1.0;
 | |
| 
 | |
| 	for (i = 0; i < n; i++) {
 | |
| 
 | |
| 		if (frac[i] > 0)
 | |
| 			continue;
 | |
| 
 | |
| 		if (min_val > frac[i]) {
 | |
| 			index = i;
 | |
| 			min_val = frac[i];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return index;
 | |
| }
 | |
| 
 | |
| static unsigned char
 | |
| int2cpt(int val)
 | |
| {
 | |
| 	if (val >= 0) {
 | |
| 
 | |
| 		if (val > 127)
 | |
| 			val = 127;
 | |
| 
 | |
| 		return (unsigned char) val;
 | |
| 
 | |
| 	} else {
 | |
| 
 | |
| 		val = -val;
 | |
| 
 | |
| 		if (val > 127)
 | |
| 			val = 127;
 | |
| 
 | |
| 		return (unsigned char) (0x80 | val);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| round_cct(double org_cct[], int rnd_cct[])
 | |
| {
 | |
| 	int loop = 0;
 | |
| 	int i, j, sum[3];
 | |
| 	double mult_cct[9], frac[9];
 | |
| 
 | |
| 	for (i = 0; i < 9; i++) {
 | |
|   		mult_cct[i] = org_cct[i] * 32;
 | |
| 		rnd_cct[i] = (int) floor(mult_cct[i] + 0.5);
 | |
| 	}
 | |
| 
 | |
| 	do {
 | |
| 		for (i = 0; i < 3; i++) {
 | |
| 
 | |
| 			int k = i * 3;
 | |
| 
 | |
| 			if ((rnd_cct[k] == 11) &&
 | |
| 				(rnd_cct[k] == rnd_cct[k + 1]) &&
 | |
| 				(rnd_cct[k] == rnd_cct[k + 2])) {
 | |
| 
 | |
| 				rnd_cct[k + i]--;
 | |
| 				mult_cct[k + i] = rnd_cct[k + i];
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		for (i = 0; i < 3; i++) {
 | |
| 
 | |
| 			int k = i * 3;
 | |
| 
 | |
| 			for (sum[i] = j = 0; j < 3; j++)
 | |
| 				sum[i] += rnd_cct[k + j];
 | |
| 		}
 | |
| 
 | |
| 		for (i = 0; i < 9; i++)
 | |
| 			frac[i] = mult_cct[i] - rnd_cct[i];
 | |
| 
 | |
| 		for (i = 0; i < 3; i++) {
 | |
| 
 | |
| 			int k = i * 3;
 | |
| 
 | |
| 			if (sum[i] < 32) {
 | |
| 
 | |
| 				int index = get_roundup_index(&frac[k], 3);
 | |
| 				if (index != -1) {
 | |
| 					rnd_cct[k + index]++;
 | |
| 					mult_cct[k + index] = rnd_cct[k + index];
 | |
| 					sum[i]++;
 | |
| 				}
 | |
| 
 | |
| 			} else if (sum[i] > 32) {
 | |
| 
 | |
| 				int index = get_rounddown_index(&frac[k], 3);
 | |
| 				if (index != -1) {
 | |
| 					rnd_cct[k + index]--;
 | |
| 					mult_cct[k + index] = rnd_cct[k + index];
 | |
| 					sum[i]--;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	while ((++loop < 2)
 | |
| 		&& ((sum[0] != 32) || (sum[1] != 32) || (sum[2] != 32)));
 | |
| }
 | |
| 
 | |
| static void
 | |
| profile_to_colorcoeff(double *profile, unsigned char *color_coeff)
 | |
| {
 | |
| 	int cc_idx[] = { 4, 1, 7, 3, 0, 6, 5, 2, 8 };
 | |
| 	int i, color_table[9];
 | |
| 
 | |
|   	round_cct(profile, color_table);
 | |
| 
 | |
|   	for (i = 0; i < 9; i++)
 | |
|   		color_coeff[i] = int2cpt(color_table[cc_idx[i]]);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Sends the "set color correction coefficients" command with the
 | |
|  * currently selected parameters to the scanner.
 | |
|  */
 | |
| 
 | |
| SANE_Status
 | |
| esci_set_color_correction_coefficients(Epson_Scanner * s, SANE_Word *table)
 | |
| {
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[2];
 | |
| 	unsigned char data[9];
 | |
| 	double cct[9];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 	if (!s->hw->cmd->set_color_correction_coefficients) {
 | |
| 		DBG(1, "%s: not supported\n", __func__);
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 	}
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->set_color_correction_coefficients;
 | |
| 
 | |
| 	status = e2_cmd_simple(s, params, 2);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	cct[0] = SANE_UNFIX(table[0]);
 | |
| 	cct[1] = SANE_UNFIX(table[1]);
 | |
| 	cct[2] = SANE_UNFIX(table[2]);
 | |
| 	cct[3] = SANE_UNFIX(table[3]);
 | |
| 	cct[4] = SANE_UNFIX(table[4]);
 | |
| 	cct[5] = SANE_UNFIX(table[5]);
 | |
| 	cct[6] = SANE_UNFIX(table[6]);
 | |
| 	cct[7] = SANE_UNFIX(table[7]);
 | |
| 	cct[8] = SANE_UNFIX(table[8]);
 | |
| 
 | |
| 	profile_to_colorcoeff(cct, data);
 | |
| 
 | |
| 	DBG(11, "%s: %d,%d,%d %d,%d,%d %d,%d,%d\n", __func__,
 | |
| 	    data[0] , data[1], data[2], data[3],
 | |
| 	    data[4], data[5], data[6], data[7], data[8]);
 | |
| 
 | |
| 	return e2_cmd_simple(s, data, 9);
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| esci_set_gamma_table(Epson_Scanner * s)
 | |
| {
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[2];
 | |
| 	unsigned char gamma[257];
 | |
| 	int n;
 | |
| 	int table;
 | |
| 
 | |
| /*	static const char gamma_cmds[] = { 'M', 'R', 'G', 'B' }; */
 | |
| 	static const char gamma_cmds[] = { 'R', 'G', 'B' };
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 	if (!s->hw->cmd->set_gamma_table)
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->set_gamma_table;
 | |
| 
 | |
| 	/* Print the gamma tables before sending them to the scanner */
 | |
| 
 | |
| 	if (DBG_LEVEL >= 16) {
 | |
| 		int c, i, j;
 | |
| 
 | |
| 		for (c = 0; c < 3; c++) {
 | |
| 			for (i = 0; i < 256; i += 16) {
 | |
| 				char gammaValues[16 * 3 + 1], newValue[4];
 | |
| 
 | |
| 				gammaValues[0] = '\0';
 | |
| 
 | |
| 				for (j = 0; j < 16; j++) {
 | |
| 					sprintf(newValue, " %02x",
 | |
| 						s->gamma_table[c][i + j]);
 | |
| 					strcat(gammaValues, newValue);
 | |
| 				}
 | |
| 
 | |
| 				DBG(16, "gamma table[%d][%d] %s\n", c, i,
 | |
| 				    gammaValues);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for (table = 0; table < 3; table++) {
 | |
| 		gamma[0] = gamma_cmds[table];
 | |
| 
 | |
| 		for (n = 0; n < 256; ++n)
 | |
| 			gamma[n + 1] = s->gamma_table[table][n];
 | |
| 
 | |
| 		status = e2_cmd_simple(s, params, 2);
 | |
| 		if (status != SANE_STATUS_GOOD)
 | |
| 			return status;
 | |
| 
 | |
| 		status = e2_cmd_simple(s, gamma, 257);
 | |
| 		if (status != SANE_STATUS_GOOD)
 | |
| 			return status;
 | |
| 	}
 | |
| 
 | |
| 	return status;
 | |
| }
 | |
| 
 | |
| /* ESC F - Request Status
 | |
|  * -> ESC f
 | |
|  * <- Information block
 | |
|  */
 | |
| 
 | |
| SANE_Status
 | |
| esci_request_status(SANE_Handle handle, unsigned char *scanner_status)
 | |
| {
 | |
| 	Epson_Scanner *s = (Epson_Scanner *) handle;
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[2];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (s->hw->cmd->request_status == 0)
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->request_status;
 | |
| 
 | |
| 	e2_send(s, params, 2, 4, &status);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	status = e2_recv_info_block(s, params, 4, NULL);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	if (scanner_status)
 | |
| 		*scanner_status = params[0];
 | |
| 
 | |
| 	DBG(1, "status: %02x\n", params[0]);
 | |
| 
 | |
| 	if (params[0] & STATUS_NOT_READY)
 | |
| 		DBG(1, " scanner in use on another interface\n");
 | |
| 	else
 | |
| 		DBG(1, " ready\n");
 | |
| 
 | |
| 	if (params[0] & STATUS_FER)
 | |
| 		DBG(1, " system error\n");
 | |
| 
 | |
| 	if (params[0] & STATUS_OPTION)
 | |
| 		DBG(1, " option equipment is installed\n");
 | |
| 	else
 | |
| 		DBG(1, " no option equipment installed\n");
 | |
| 
 | |
| 	if (params[0] & STATUS_EXT_COMMANDS)
 | |
| 		DBG(1, " support extended commands\n");
 | |
| 	else
 | |
| 		DBG(1, " does NOT support extended commands\n");
 | |
| 
 | |
| 	if (params[0] & STATUS_RESERVED)
 | |
| 		DBG(0,
 | |
| 		    " a reserved bit is set, please contact the author.\n");
 | |
| 
 | |
| 	return status;
 | |
| }
 | |
| 
 | |
| /* extended commands */
 | |
| 
 | |
| /* FS I, Request Extended Identity
 | |
|  * -> FS I
 | |
|  * <- Extended identity data (80)
 | |
|  *
 | |
|  * Request the properties of the scanner.
 | |
|  */
 | |
| 
 | |
| SANE_Status
 | |
| esci_request_extended_identity(SANE_Handle handle, unsigned char *buf)
 | |
| {
 | |
| 	unsigned char model[17];
 | |
| 	Epson_Scanner *s = (Epson_Scanner *) handle;
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[2];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (buf == NULL)
 | |
| 		return SANE_STATUS_INVAL;
 | |
| 
 | |
| 	if (s->hw->cmd->request_extended_identity == 0)
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 
 | |
| 	params[0] = FS;
 | |
| 	params[1] = s->hw->cmd->request_extended_identity;
 | |
| 
 | |
| 	status = e2_txrx(s, params, 2, buf, 80);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	DBG(1, " command level   : %c%c\n", buf[0], buf[1]);
 | |
| 	DBG(1, " basic resolution: %lu\n", (unsigned long) le32atoh(&buf[4]));
 | |
| 	DBG(1, " min resolution  : %lu\n", (unsigned long) le32atoh(&buf[8]));
 | |
| 	DBG(1, " max resolution  : %lu\n", (unsigned long) le32atoh(&buf[12]));
 | |
| 	DBG(1, " max pixel num   : %lu\n", (unsigned long) le32atoh(&buf[16]));
 | |
| 	DBG(1, " scan area       : %lux%lu\n",
 | |
| 	    (unsigned long) le32atoh(&buf[20]), (unsigned long) le32atoh(&buf[24]));
 | |
| 
 | |
| 	DBG(1, " adf area        : %lux%lu\n",
 | |
| 	    (unsigned long) le32atoh(&buf[28]), (unsigned long) le32atoh(&buf[32]));
 | |
| 
 | |
| 	DBG(1, " tpu area        : %lux%lu\n",
 | |
| 	    (unsigned long) le32atoh(&buf[36]), (unsigned long) le32atoh(&buf[40]));
 | |
| 
 | |
| 	DBG(1, " capabilities (1): 0x%02x\n", buf[44]);
 | |
| 	DBG(1, " capabilities (2): 0x%02x\n", buf[45]);
 | |
| 	DBG(1, " input depth     : %d\n", buf[66]);
 | |
| 	DBG(1, " max output depth: %d\n", buf[67]);
 | |
| 	DBG(1, " rom version     : %c%c%c%c\n",
 | |
| 	    buf[62], buf[63], buf[64], buf[65]);
 | |
| 
 | |
| 	memcpy(model, &buf[46], 16);
 | |
| 	model[16] = '\0';
 | |
| 	DBG(1, " model name      : %s\n", model);
 | |
| 
 | |
| 	DBG(1, "options:\n");
 | |
| 
 | |
| 	if (le32atoh(&buf[28]) > 0)
 | |
| 		DBG(1, " ADF detected\n");
 | |
| 
 | |
| 	if (le32atoh(&buf[36]) > 0)
 | |
| 		DBG(1, " TPU detected\n");
 | |
| 
 | |
| 	if (buf[44])
 | |
| 		DBG(1, "capabilities (1):\n");
 | |
| 
 | |
| 	if (buf[44] & EXT_IDTY_CAP1_DLF)
 | |
| 		DBG(1, " main lamp change is supported\n");
 | |
| 
 | |
| 	if (buf[44] & EXT_IDTY_CAP1_NOTFBF)
 | |
| 		DBG(1, " the device is NOT flatbed\n");
 | |
| 
 | |
| 	if (buf[44] & EXT_IDTY_CAP1_ADFT)
 | |
| 		DBG(1, " page type ADF is installed\n");
 | |
| 
 | |
| 	if (buf[44] & EXT_IDTY_CAP1_ADFS)
 | |
| 		DBG(1, " ADF is duplex capable\n");
 | |
| 
 | |
| 	if (buf[44] & EXT_IDTY_CAP1_ADFO)
 | |
| 		DBG(1, " page type ADF loads from the first sheet\n");
 | |
| 
 | |
| 	if (buf[44] & EXT_IDTY_CAP1_LID)
 | |
| 		DBG(1, " lid type option is installed\n");
 | |
| 
 | |
| 	if (buf[44] & EXT_IDTY_CAP1_TPIR)
 | |
| 		DBG(1, " infrared scanning is supported\n");
 | |
| 
 | |
| 	if (buf[44] & EXT_IDTY_CAP1_PB)
 | |
| 		DBG(1, " push button is supported\n");
 | |
| 
 | |
| 
 | |
| 	if (buf[45])
 | |
| 		DBG(1, "capabilities (2):\n");
 | |
| 
 | |
| 	if (buf[45] & EXT_IDTY_CAP2_AFF)
 | |
| 		DBG(1, " ADF has auto form feed\n");
 | |
| 
 | |
| 	if (buf[45] & EXT_IDTY_CAP2_DFD)
 | |
| 		DBG(1, " ADF has double feed detection\n");
 | |
| 
 | |
| 	if (buf[45] & EXT_IDTY_CAP2_ADFAS)
 | |
| 		DBG(1, " ADF has auto scan\n");
 | |
| 
 | |
| 	return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| /* FS F, request scanner status */
 | |
| SANE_Status
 | |
| esci_request_scanner_status(SANE_Handle handle, unsigned char *buf)
 | |
| {
 | |
| 	Epson_Scanner *s = (Epson_Scanner *) handle;
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[2];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (!s->hw->extended_commands)
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 
 | |
| 	if (buf == NULL)
 | |
| 		return SANE_STATUS_INVAL;
 | |
| 
 | |
| 	params[0] = FS;
 | |
| 	params[1] = 'F';
 | |
| 
 | |
| 	status = e2_txrx(s, params, 2, buf, 16);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	DBG(1, "global status   : 0x%02x\n", buf[0]);
 | |
| 
 | |
| 	if (buf[0] & FSF_STATUS_MAIN_FER)
 | |
| 		DBG(1, " system error\n");
 | |
| 
 | |
| 	if (buf[0] & FSF_STATUS_MAIN_NR)
 | |
| 		DBG(1, " not ready\n");
 | |
| 
 | |
| 	if (buf[0] & FSF_STATUS_MAIN_WU)
 | |
| 		DBG(1, " scanner is warming up\n");
 | |
| 
 | |
| 	if (buf[0] & FSF_STATUS_MAIN_CWU)
 | |
| 		DBG(1, " warmup can be cancelled\n");
 | |
| 
 | |
| 
 | |
| 	DBG(1, "adf status      : 0x%02x\n", buf[1]);
 | |
| 
 | |
| 	if (buf[1] & FSF_STATUS_ADF_IST)
 | |
| 		DBG(11, " installed\n");
 | |
| 	else
 | |
| 		DBG(11, " not installed\n");
 | |
| 
 | |
| 	if (buf[1] & FSF_STATUS_ADF_EN)
 | |
| 		DBG(11, " enabled\n");
 | |
| 	else
 | |
| 		DBG(11, " not enabled\n");
 | |
| 
 | |
| 	if (buf[1] & FSF_STATUS_ADF_ERR)
 | |
| 		DBG(1, " error\n");
 | |
| 
 | |
| 	if (buf[1] & FSF_STATUS_ADF_PE)
 | |
| 		DBG(1, " paper empty\n");
 | |
| 
 | |
| 	if (buf[1] & FSF_STATUS_ADF_PJ)
 | |
| 		DBG(1, " paper jam\n");
 | |
| 
 | |
| 	if (buf[1] & FSF_STATUS_ADF_OPN)
 | |
| 		DBG(1, " cover open\n");
 | |
| 
 | |
| 	if (buf[1] & FSF_STATUS_ADF_PAG)
 | |
| 		DBG(1, " duplex capable\n");
 | |
| 
 | |
| 
 | |
| 	DBG(1, "tpu status      : 0x%02x\n", buf[2]);
 | |
| 
 | |
| 	if (buf[2] & FSF_STATUS_TPU_IST)
 | |
| 		DBG(11, " installed\n");
 | |
| 	else
 | |
| 		DBG(11, " not installed\n");
 | |
| 
 | |
| 	if (buf[2] & FSF_STATUS_TPU_EN)
 | |
| 		DBG(11, " enabled\n");
 | |
| 	else
 | |
| 		DBG(11, " not enabled\n");
 | |
| 
 | |
| 	if (buf[2] & FSF_STATUS_TPU_ERR)
 | |
| 		DBG(1, " error\n");
 | |
| 
 | |
| 	if (buf[1] & FSF_STATUS_TPU_OPN)
 | |
| 		DBG(1, " cover open\n");
 | |
| 
 | |
| 
 | |
| 	DBG(1, "device type     : 0x%02x\n", buf[3] & 0xC0);
 | |
| 	DBG(1, "main body status: 0x%02x\n", buf[3] & 0x3F);
 | |
| 
 | |
| 	if (buf[3] & FSF_STATUS_MAIN2_PE)
 | |
| 		DBG(1, " paper empty\n");
 | |
| 
 | |
| 	if (buf[3] & FSF_STATUS_MAIN2_PJ)
 | |
| 		DBG(1, " paper jam\n");
 | |
| 
 | |
| 	if (buf[3] & FSF_STATUS_MAIN2_OPN)
 | |
| 		DBG(1, " cover open\n");
 | |
| 
 | |
| 	return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| esci_set_scanning_parameter(SANE_Handle handle, unsigned char *buf)
 | |
| {
 | |
| 	Epson_Scanner *s = (Epson_Scanner *) handle;
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[2];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (buf == NULL)
 | |
| 		return SANE_STATUS_INVAL;
 | |
| 
 | |
| 	params[0] = FS;
 | |
| 	params[1] = 'W';
 | |
| 
 | |
| 	DBG(10, "resolution of main scan     : %lu\n", (unsigned long) le32atoh(&buf[0]));
 | |
| 	DBG(10, "resolution of sub scan      : %lu\n", (unsigned long) le32atoh(&buf[4]));
 | |
| 	DBG(10, "offset length of main scan  : %lu\n", (unsigned long) le32atoh(&buf[8]));
 | |
| 	DBG(10, "offset length of sub scan   : %lu\n", (unsigned long) le32atoh(&buf[12]));
 | |
| 	DBG(10, "scanning length of main scan: %lu\n", (unsigned long) le32atoh(&buf[16]));
 | |
| 	DBG(10, "scanning length of sub scan : %lu\n", (unsigned long) le32atoh(&buf[20]));
 | |
| 	DBG(10, "scanning color              : %d\n", buf[24]);
 | |
| 	DBG(10, "data format                 : %d\n", buf[25]);
 | |
| 	DBG(10, "option control              : %d\n", buf[26]);
 | |
| 	DBG(10, "scanning mode               : %d\n", buf[27]);
 | |
| 	DBG(10, "block line number           : %d\n", buf[28]);
 | |
| 	DBG(10, "gamma correction            : %d\n", buf[29]);
 | |
| 	DBG(10, "brightness                  : %d\n", buf[30]);
 | |
| 	DBG(10, "color correction            : %d\n", buf[31]);
 | |
| 	DBG(10, "halftone processing         : %d\n", buf[32]);
 | |
| 	DBG(10, "threshold                   : %d\n", buf[33]);
 | |
| 	DBG(10, "auto area segmentation      : %d\n", buf[34]);
 | |
| 	DBG(10, "sharpness control           : %d\n", buf[35]);
 | |
| 	DBG(10, "mirroring                   : %d\n", buf[36]);
 | |
| 	DBG(10, "film type                   : %d\n", buf[37]);
 | |
| 	DBG(10, "main lamp lighting mode     : %d\n", buf[38]);
 | |
| 
 | |
| 	status = e2_cmd_simple(s, params, 2);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	status = e2_cmd_simple(s, buf, 64);
 | |
| 	if (status != SANE_STATUS_GOOD) {
 | |
| 		DBG(1, "%s: invalid scanning parameters\n", __func__);
 | |
| 		return status;
 | |
| 	}
 | |
| 
 | |
| 	return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| /* FS S */
 | |
| 
 | |
| SANE_Status
 | |
| esci_get_scanning_parameter(SANE_Handle handle, unsigned char *buf)
 | |
| {
 | |
| 	Epson_Scanner *s = (Epson_Scanner *) handle;
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[2];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (buf == NULL)
 | |
| 		return SANE_STATUS_INVAL;
 | |
| 
 | |
| 	params[0] = FS;
 | |
| 	params[1] = 'S';
 | |
| 
 | |
| 	status = e2_txrx(s, params, 2, buf, 64);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	DBG(10, "resolution of main scan     : %lu\n",
 | |
| 	    (u_long) le32atoh(&buf[0]));
 | |
| 	DBG(10, "resolution of sub scan      : %lu\n",
 | |
| 	    (u_long) le32atoh(&buf[4]));
 | |
| 	DBG(10, "offset length of main scan  : %lu\n",
 | |
| 	    (u_long) le32atoh(&buf[8]));
 | |
| 	DBG(10, "offset length of sub scan   : %lu\n",
 | |
| 	    (u_long) le32atoh(&buf[12]));
 | |
| 	DBG(10, "scanning length of main scan: %lu\n",
 | |
| 	    (u_long) le32atoh(&buf[16]));
 | |
| 	DBG(10, "scanning length of sub scan : %lu\n",
 | |
| 	    (u_long) le32atoh(&buf[20]));
 | |
| 	DBG(10, "scanning color              : %d\n", buf[24]);
 | |
| 	DBG(10, "data format                 : %d\n", buf[25]);
 | |
| 	DBG(10, "option control              : %d\n", buf[26]);
 | |
| 	DBG(10, "scanning mode               : %d\n", buf[27]);
 | |
| 	DBG(10, "block line number           : %d\n", buf[28]);
 | |
| 	DBG(10, "gamma correction            : %d\n", buf[29]);
 | |
| 	DBG(10, "brightness                  : %d\n", buf[30]);
 | |
| 	DBG(10, "color correction            : %d\n", buf[31]);
 | |
| 	DBG(10, "halftone processing         : %d\n", buf[32]);
 | |
| 	DBG(10, "threshold                   : %d\n", buf[33]);
 | |
| 	DBG(10, "auto area segmentation      : %d\n", buf[34]);
 | |
| 	DBG(10, "sharpness control           : %d\n", buf[35]);
 | |
| 	DBG(10, "mirroring                   : %d\n", buf[36]);
 | |
| 	DBG(10, "film type                   : %d\n", buf[37]);
 | |
| 	DBG(10, "main lamp lighting mode     : %d\n", buf[38]);
 | |
| 
 | |
| 	return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| /* ESC # */
 | |
| 
 | |
| SANE_Status
 | |
| esci_enable_infrared(SANE_Handle handle)
 | |
| {
 | |
| 	Epson_Scanner *s = (Epson_Scanner *) handle;
 | |
| 	SANE_Status status;
 | |
| 	int i;
 | |
| 	unsigned char params[2];
 | |
| 	unsigned char buf[64];
 | |
| 
 | |
| 	unsigned char seq[32] = {
 | |
| 		0xCA, 0xFB, 0x77, 0x71, 0x20, 0x16, 0xDA, 0x09,
 | |
| 		0x5F, 0x57, 0x09, 0x12, 0x04, 0x83, 0x76, 0x77,
 | |
| 		0x3C, 0x73, 0x9C, 0xBE, 0x7A, 0xE0, 0x52, 0xE2,
 | |
| 		0x90, 0x0D, 0xFF, 0x9A, 0xEF, 0x4C, 0x2C, 0x81
 | |
| 	};
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	status = esci_get_scanning_parameter(handle, buf);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	for (i = 0; i < 32; i++) {
 | |
| 		buf[i] = seq[i] ^ buf[i];
 | |
| 	}
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = '#';
 | |
| 
 | |
| 	status = e2_cmd_simple(s, params, 2);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	status = e2_cmd_simple(s, buf, 32);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	return SANE_STATUS_GOOD;
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| esci_request_command_parameter(SANE_Handle handle, unsigned char *buf)
 | |
| {
 | |
| 	Epson_Scanner *s = (Epson_Scanner *) handle;
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[2];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (s->hw->cmd->request_condition == 0)
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->request_condition;
 | |
| 
 | |
| 	status = e2_cmd_info_block(s, params, 2, 45, &buf, NULL);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	DBG(1, "scanning parameters:\n");
 | |
| 	DBG(1, "color                  : %d\n", buf[1]);
 | |
| 	DBG(1, "resolution             : %dx%d\n",
 | |
| 	    buf[4] << 8 | buf[3], buf[6] << 8 | buf[5]);
 | |
| 	DBG(1, "halftone               : %d\n", buf[19]);
 | |
| 	DBG(1, "brightness             : %d\n", buf[21]);
 | |
| 	DBG(1, "color correction       : %d\n", buf[28]);
 | |
| 	DBG(1, "gamma                  : %d\n", buf[23]);
 | |
| 	DBG(1, "sharpness              : %d\n", buf[30]);
 | |
| 	DBG(1, "threshold              : %d\n", buf[38]);
 | |
| 	DBG(1, "data format            : %d\n", buf[17]);
 | |
| 	DBG(1, "mirroring              : %d\n", buf[34]);
 | |
| 	DBG(1, "option unit control    : %d\n", buf[42]);
 | |
| 	DBG(1, "film type              : %d\n", buf[44]);
 | |
| 	DBG(1, "auto area segmentation : %d\n", buf[36]);
 | |
| 	DBG(1, "line counter           : %d\n", buf[40]);
 | |
| 	DBG(1, "scanning mode          : %d\n", buf[32]);
 | |
| 	DBG(1, "zoom                   : %d,%d\n", buf[26], buf[25]);
 | |
| 	DBG(1, "scan area              : %d,%d %d,%d\n",
 | |
| 	    buf[9] << 8 | buf[8], buf[11] << 8 | buf[10],
 | |
| 	    buf[13] << 8 | buf[12], buf[15] << 8 | buf[14]);
 | |
| 	return status;
 | |
| }
 | |
| 
 | |
| /* ESC q - Request Focus Position
 | |
|  * -> ESC q
 | |
|  * <- Information block
 | |
|  * <- Focus position status (2)
 | |
|  *	0 - Error status
 | |
|  *	1 - Focus position
 | |
|  */
 | |
| 
 | |
| SANE_Status
 | |
| esci_request_focus_position(SANE_Handle handle, unsigned char *position)
 | |
| {
 | |
| 	SANE_Status status;
 | |
| 	unsigned char *buf;
 | |
| 	Epson_Scanner *s = (Epson_Scanner *) handle;
 | |
| 
 | |
| 	unsigned char params[2];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (s->hw->cmd->request_focus_position == 0)
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->request_focus_position;
 | |
| 
 | |
| 	status = e2_cmd_info_block(s, params, 2, 2, &buf, NULL);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	if (buf[0] & 0x01)
 | |
| 		DBG(1, "autofocus error\n");
 | |
| 
 | |
| 	*position = buf[1];
 | |
| 	DBG(8, " focus position = 0x%x\n", buf[1]);
 | |
| 
 | |
| 	free(buf);
 | |
| 
 | |
| 	return status;
 | |
| }
 | |
| 
 | |
| /* ESC ! - Request Push Button Status
 | |
|  * -> ESC !
 | |
|  * <- Information block
 | |
|  * <- Push button status (1)
 | |
|  */
 | |
| 
 | |
| SANE_Status
 | |
| esci_request_push_button_status(SANE_Handle handle, unsigned char *bstatus)
 | |
| {
 | |
| 	Epson_Scanner *s = (Epson_Scanner *) handle;
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[2];
 | |
| 	unsigned char *buf;
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (s->hw->cmd->request_push_button_status == 0) {
 | |
| 		DBG(1, "push button status unsupported\n");
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 	}
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->request_push_button_status;
 | |
| 
 | |
| 	status = e2_cmd_info_block(s, params, 2, 1, &buf, NULL);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	DBG(1, "push button status = %d\n", buf[0]);
 | |
| 	*bstatus = buf[0];
 | |
| 
 | |
| 	free(buf);
 | |
| 
 | |
| 	return status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Request Identity information from scanner and fill in information
 | |
|  * into dev and/or scanner structures.
 | |
|  * XXX information should be parsed separately.
 | |
|  */
 | |
| SANE_Status
 | |
| esci_request_identity(SANE_Handle handle, unsigned char **buf, size_t *len)
 | |
| {
 | |
| 	Epson_Scanner *s = (Epson_Scanner *) handle;
 | |
| 	unsigned char params[2];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (!s->hw->cmd->request_identity)
 | |
| 		return SANE_STATUS_INVAL;
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->request_identity;
 | |
| 
 | |
| 	return e2_cmd_info_block(s, params, 2, 0, buf, len);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Request information from scanner
 | |
|  */
 | |
| SANE_Status
 | |
| esci_request_identity2(SANE_Handle handle, unsigned char **buf)
 | |
| {
 | |
| 	Epson_Scanner *s = (Epson_Scanner *) handle;
 | |
| 	SANE_Status status;
 | |
| 	size_t len;
 | |
| 	unsigned char params[2];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (s->hw->cmd->request_identity2 == 0)
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->request_identity2;
 | |
| 
 | |
| 	status = e2_cmd_info_block(s, params, 2, 0, buf, &len);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	return status;
 | |
| }
 | |
| 
 | |
| /* Send the "initialize scanner" command to the device and reset it */
 | |
| 
 | |
| SANE_Status
 | |
| esci_reset(Epson_Scanner * s)
 | |
| {
 | |
| 	SANE_Status status;
 | |
| 	unsigned char params[2];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (!s->hw->cmd->initialize_scanner)
 | |
| 		return SANE_STATUS_GOOD;
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->initialize_scanner;
 | |
| 
 | |
| 	if (s->fd == -1)
 | |
| 		return SANE_STATUS_GOOD;
 | |
| 
 | |
| 	status = e2_cmd_simple(s, params, 2);
 | |
| 
 | |
| 	return status;
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| esci_feed(Epson_Scanner * s)
 | |
| {
 | |
| 	unsigned char params[1];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (!s->hw->cmd->feed)
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 
 | |
| 	params[0] = s->hw->cmd->feed;
 | |
| 
 | |
| 	return e2_cmd_simple(s, params, 1);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Eject the current page from the ADF. The scanner is opened prior to
 | |
|  * sending the command and closed afterwards.
 | |
|  */
 | |
| 
 | |
| SANE_Status
 | |
| esci_eject(Epson_Scanner * s)
 | |
| {
 | |
| 	unsigned char params[1];
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (!s->hw->cmd->eject)
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 
 | |
| 	if (s->fd == -1)
 | |
| 		return SANE_STATUS_GOOD;
 | |
| 
 | |
| 	params[0] = s->hw->cmd->eject;
 | |
| 
 | |
| 	return e2_cmd_simple(s, params, 1);
 | |
| }
 | |
| 
 | |
| SANE_Status
 | |
| esci_request_extended_status(SANE_Handle handle, unsigned char **data,
 | |
| 			size_t * data_len)
 | |
| {
 | |
| 	Epson_Scanner *s = (Epson_Scanner *) handle;
 | |
| 	SANE_Status status = SANE_STATUS_GOOD;
 | |
| 	unsigned char params[2];
 | |
| 	unsigned char *buf;
 | |
| 	size_t buf_len;
 | |
| 
 | |
| 	DBG(8, "%s\n", __func__);
 | |
| 
 | |
| 	if (s->hw->cmd->request_extended_status == 0)
 | |
| 		return SANE_STATUS_UNSUPPORTED;
 | |
| 
 | |
| 	params[0] = ESC;
 | |
| 	params[1] = s->hw->cmd->request_extended_status;
 | |
| 
 | |
| 	/* This command returns 33 bytes of data on old scanners
 | |
| 	 * and 42 (CMD_SIZE_EXT_STATUS) on new ones.
 | |
| 	 */
 | |
| 	status = e2_cmd_info_block(s, params, 2, CMD_SIZE_EXT_STATUS,
 | |
| 				       &buf, &buf_len);
 | |
| 	if (status != SANE_STATUS_GOOD)
 | |
| 		return status;
 | |
| 
 | |
| 	switch (buf_len) {
 | |
| 	case 33:
 | |
| 	case 42:
 | |
| 		break;
 | |
| 	default:
 | |
| 		DBG(1, "%s: unknown reply length (%lu)\n", __func__,
 | |
| 			(unsigned long) buf_len);
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	DBG(4, "main = %02x, ADF = %02x, TPU = %02x, main 2 = %02x\n",
 | |
| 		buf[0], buf[1], buf[6], buf[11]);
 | |
| 
 | |
| 	if (buf[0] & EXT_STATUS_FER)
 | |
| 		DBG(1, "system error\n");
 | |
| 
 | |
| 	if (buf[0] & EXT_STATUS_WU)
 | |
| 		DBG(1, "scanner is warming up\n");
 | |
| 
 | |
| 	if (buf[1] & EXT_STATUS_ERR)
 | |
| 		DBG(1, "ADF: other error\n");
 | |
| 
 | |
| 	if (buf[1] & EXT_STATUS_PE)
 | |
| 		DBG(1, "ADF: no paper\n");
 | |
| 
 | |
| 	if (buf[1] & EXT_STATUS_PJ)
 | |
| 		DBG(1, "ADF: paper jam\n");
 | |
| 
 | |
| 	if (buf[1] & EXT_STATUS_OPN)
 | |
| 		DBG(1, "ADF: cover open\n");
 | |
| 
 | |
| 	if (buf[6] & EXT_STATUS_ERR)
 | |
| 		DBG(1, "TPU: other error\n");
 | |
| 
 | |
| 	/* give back a pointer to the payload
 | |
| 	 * if the user requested it, otherwise
 | |
| 	 * free it.
 | |
| 	 */
 | |
| 
 | |
| 	if (data)
 | |
| 		*data = buf;
 | |
| 	else
 | |
| 		free(buf);
 | |
| 
 | |
| 	if (data_len)
 | |
| 		*data_len = buf_len;
 | |
| 
 | |
| 	return status;
 | |
| }
 |