* backend/canon_pp.c backend/canon_pp-dev.c backend/caon_pp-io.c

backend/canon_pp-dev.h: Many changes: Bug fixes, less memory leaks                                       (none left now?), more relaible, faster.  Biggest changes are                                            speculative reads (ask scanner to read more while data processing
occurs) and more reliable sending of commands.  Slight performance
increase over previous version.
* doc/sane-canon_pp.man: Added discussion noting that scanning
greyscale in green is bad for colour.
DEVEL_2_0_BRANCH-1
Matthew Duggan 2002-08-07 07:56:12 +00:00
rodzic f7806b4492
commit 4a552e1540
3 zmienionych plików z 100 dodań i 148 usunięć

Wyświetl plik

@ -65,7 +65,7 @@ static void DBG(int level, const char *format, ...)
{ {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
vfprintf(stderr, format, args); if (level < 50) vfprintf(stderr, format, args);
va_end(args); va_end(args);
} }
#else #else
@ -88,12 +88,8 @@ static void DBG(int level, const char *format, ...)
*/ */
static int ieee_mode = M1284_NIBBLE; static int ieee_mode = M1284_NIBBLE;
static const int verbose = 0; /* For super-verbose debugging */
static const int dump_packets = 0; /* #define DUMP_PACKETS 0; */
/* This is just for the time being. We need a way to turn on
and off status messages so that wait loops involving sending
commands don't obscure the program's status log. */
/* Unknown command 1 */ /* Unknown command 1 */
static unsigned char command_1[10] = { 0xec, 0x20, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char command_1[10] = { 0xec, 0x20, 0, 0, 0, 0, 0, 0, 0, 0 };
@ -176,10 +172,10 @@ int sanei_canon_pp_wake_scanner(struct parport *port)
int sanei_canon_pp_write(struct parport *port, int length, unsigned char *data) int sanei_canon_pp_write(struct parport *port, int length, unsigned char *data)
{ {
#ifdef DUMP_PACKETS
ssize_t count; ssize_t count;
if (dump_packets)
{
DBG(10,"Sent: "); DBG(10,"Sent: ");
for (count = 0; count < length; count++) for (count = 0; count < length; count++)
{ {
@ -188,10 +184,9 @@ int sanei_canon_pp_write(struct parport *port, int length, unsigned char *data)
DBG(10,"\n "); DBG(10,"\n ");
} }
if (count % 20 != 19) DBG(10,"\n"); if (count % 20 != 19) DBG(10,"\n");
} #endif
if (verbose) DBG(100, "NEW Send Command (length %i):\n", length);
DBG(10, "NEW Send Command (length %i):\n", length);
if (ieee_mode == M1284_ECP) if (ieee_mode == M1284_ECP)
ieee_negotiation(port, ieee_mode); ieee_negotiation(port, ieee_mode);
@ -216,8 +211,7 @@ int sanei_canon_pp_read(struct parport *port, int length, unsigned char *data)
{ {
int count, offset; int count, offset;
if (verbose) DBG(200, "NEW read_data (%i bytes):\n", length);
DBG(10, "NEW read_data (%i bytes):\n", length);
ieee_negotiation(port, ieee_mode); ieee_negotiation(port, ieee_mode);
/* This is special; Nibble mode needs a little /* This is special; Nibble mode needs a little
@ -282,8 +276,7 @@ int sanei_canon_pp_read(struct parport *port, int length, unsigned char *data)
} }
if (dump_packets) #ifdef DUMP_PACKETS
{
if (length <= 60) if (length <= 60)
{ {
DBG(10,"Read: "); DBG(10,"Read: ");
@ -300,7 +293,7 @@ int sanei_canon_pp_read(struct parport *port, int length, unsigned char *data)
{ {
DBG(10,"Read: %i bytes\n", length); DBG(10,"Read: %i bytes\n", length);
} }
} #endif
scanner_endtransfer(port); scanner_endtransfer(port);
return 0; return 0;
@ -317,13 +310,11 @@ static int ieee_negotiation(struct parport *port, int e)
{ {
int temp; int temp;
if (verbose) DBG(200, "IEEE Negotiation (mode %i)\n", e);
DBG(10, "IEEE Negotiation (mode %i)\n", e);
temp = ieee1284_negotiate(port, e); temp = ieee1284_negotiate(port, e);
if (verbose) DBG(200, "(result: %i)\n", temp);
DBG(10, "result: %i)\n", temp);
return temp; return temp;
} }
@ -332,8 +323,7 @@ static int ieee_transfer(struct parport *port, int length, unsigned char *data)
{ {
int result = 0; int result = 0;
if (verbose) DBG(200, "IEEE transfer (%i bytes)\n", length);
DBG(10, "IEEE transfer (%i bytes)\n", length);
switch (ieee_mode) switch (ieee_mode)
{ {
@ -355,8 +345,7 @@ int sanei_canon_pp_check_status(struct parport *port)
int status; int status;
unsigned char data[2]; unsigned char data[2];
if (verbose) DBG(200, "* Check Status:\n");
DBG(10, "* Check Status:\n");
if (sanei_canon_pp_read(port, 2, data)) if (sanei_canon_pp_read(port, 2, data))
return -1; return -1;
@ -366,15 +355,15 @@ int sanei_canon_pp_check_status(struct parport *port)
switch(status) switch(status)
{ {
case 0x0606: case 0x0606:
if (verbose) DBG(10, "Ready - 0x0606\n"); DBG(200, "Ready - 0x0606\n");
return 0; return 0;
break; break;
case 0x1414: case 0x1414:
if (verbose) DBG(10, "Busy - 0x1414\n"); DBG(200, "Busy - 0x1414\n");
return 1; return 1;
break; break;
case 0x0805: case 0x0805:
if (verbose) DBG(10, "Resetting - 0x0805\n"); DBG(200, "Resetting - 0x0805\n");
return 3; return 3;
break; break;
case 0x1515: case 0x1515:
@ -390,8 +379,7 @@ int sanei_canon_pp_check_status(struct parport *port)
/* This is a subfunction of scanner_readdata() */ /* This is a subfunction of scanner_readdata() */
static int scanner_endtransfer(struct parport *port) static int scanner_endtransfer(struct parport *port)
{ {
if (verbose) DBG(200, ">> IEEE Terminate\n");
DBG(40, ">> IEEE Terminate\n");
ieee1284_terminate(port); ieee1284_terminate(port);
return 0; return 0;
} }

Wyświetl plik

@ -58,6 +58,7 @@
#define MM_PER_IN 25.4 #define MM_PER_IN 25.4
#include <string.h> #include <string.h>
#include <math.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
@ -405,9 +406,9 @@ sane_get_devices (const SANE_Device ***dl, SANE_Bool local)
*dl = devlist; *dl = devlist;
return SANE_STATUS_GOOD; return SANE_STATUS_GOOD;
} }
devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); devlist = malloc((num_devices + 1) * sizeof(*devlist));
if (devlist == NULL) if (devlist == NULL)
return (SANE_STATUS_NO_MEM); return SANE_STATUS_NO_MEM;
i = 0; i = 0;
for (dev = first_dev; dev != NULL; dev = dev->next) for (dev = first_dev; dev != NULL; dev = dev->next)
@ -576,28 +577,28 @@ sane_open (SANE_String_Const name, SANE_Handle *h)
/* TL-X */ /* TL-X */
if(!(tmp_range = (SANE_Range *)malloc(sizeof(SANE_Range)))) if(!(tmp_range = malloc(sizeof(*tmp_range))))
return SANE_STATUS_NO_MEM; return SANE_STATUS_NO_MEM;
(*tmp_range).min = 0; (*tmp_range).min = 0;
(*tmp_range).max = 215; (*tmp_range).max = 215;
cs->opt[OPT_TL_X].constraint.range = tmp_range; cs->opt[OPT_TL_X].constraint.range = tmp_range;
/* TL-Y */ /* TL-Y */
if(!(tmp_range = (SANE_Range *)malloc(sizeof(SANE_Range)))) if(!(tmp_range = malloc(sizeof(*tmp_range))))
return SANE_STATUS_NO_MEM; return SANE_STATUS_NO_MEM;
(*tmp_range).min = 0; (*tmp_range).min = 0;
(*tmp_range).max = 296; (*tmp_range).max = 296;
cs->opt[OPT_TL_Y].constraint.range = tmp_range; cs->opt[OPT_TL_Y].constraint.range = tmp_range;
/* BR-X */ /* BR-X */
if(!(tmp_range = (SANE_Range *)malloc(sizeof(SANE_Range)))) if(!(tmp_range = malloc(sizeof(*tmp_range))))
return SANE_STATUS_NO_MEM; return SANE_STATUS_NO_MEM;
(*tmp_range).min = 22; (*tmp_range).min = 22;
(*tmp_range).max = 216; (*tmp_range).max = 216;
cs->opt[OPT_BR_X].constraint.range = tmp_range; cs->opt[OPT_BR_X].constraint.range = tmp_range;
/* BR-Y */ /* BR-Y */
if(!(tmp_range = (SANE_Range *)malloc(sizeof(SANE_Range)))) if(!(tmp_range = malloc(sizeof(*tmp_range))))
return SANE_STATUS_NO_MEM; return SANE_STATUS_NO_MEM;
(*tmp_range).min = 1; (*tmp_range).min = 1;
(*tmp_range).max = 297; (*tmp_range).max = 297;
@ -854,7 +855,6 @@ sane_get_parameters (SANE_Handle h, SANE_Parameters *params)
{ {
int res, max_width, max_height, max_res; int res, max_width, max_height, max_res;
CANONP_Scanner *cs = ((CANONP_Scanner *)h); CANONP_Scanner *cs = ((CANONP_Scanner *)h);
SANE_Int total_lines = 0;
DBG(2, ">> sane_get_parameters (h=%p, params=%p)\n", h, params); DBG(2, ">> sane_get_parameters (h=%p, params=%p)\n", h, params);
if (h == NULL) return SANE_STATUS_INVAL; if (h == NULL) return SANE_STATUS_INVAL;
@ -879,7 +879,7 @@ sane_get_parameters (SANE_Handle h, SANE_Parameters *params)
/* Copy the options stored in the vals into the scaninfo */ /* Copy the options stored in the vals into the scaninfo */
params->pixels_per_line = params->pixels_per_line =
((cs->vals[OPT_BR_X] - cs->vals[OPT_TL_X]) * res) / MM_PER_IN; ((cs->vals[OPT_BR_X] - cs->vals[OPT_TL_X]) * res) / MM_PER_IN;
total_lines = ((cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y]) * res) params->lines = ((cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y]) * res)
/ MM_PER_IN; / MM_PER_IN;
/* FIXME: Magic numbers ahead! */ /* FIXME: Magic numbers ahead! */
@ -899,7 +899,7 @@ sane_get_parameters (SANE_Handle h, SANE_Parameters *params)
if(params->pixels_per_line > max_width) if(params->pixels_per_line > max_width)
params->pixels_per_line = max_width; params->pixels_per_line = max_width;
if(total_lines > max_height) total_lines = max_height; if(params->lines > max_height) params->lines = max_height;
params->depth = cs->vals[OPT_DEPTH] ? 16 : 8; params->depth = cs->vals[OPT_DEPTH] ? 16 : 8;
@ -923,41 +923,18 @@ sane_get_parameters (SANE_Handle h, SANE_Parameters *params)
params->lines = 0; params->lines = 0;
} }
/* Always assume next packet will be the last /* Always the "last frame" */
* - frontends seem to like it that way */
params->last_frame = SANE_TRUE; params->last_frame = SANE_TRUE;
switch (cs->vals[OPT_COLOUR_MODE]) params->bytes_per_line = params->pixels_per_line * (params->depth/8) *
{ (cs->vals[OPT_COLOUR_MODE] ? 3 : 1);
case 0: /* Grey */
params->bytes_per_line =
params->pixels_per_line * (params->depth/8);
break;
case 1: /* Colour */
params->bytes_per_line =
params->pixels_per_line * (params->depth/8) * 3;
break;
default:
/* shouldn't happen */
break;
}
if (cs->bytes_sent > 0)
/* we want to round up the number of lines still to come */
params->lines = total_lines -
ceilf((float)(cs->bytes_sent) /
(float)(params->bytes_per_line));
else
params->lines = total_lines;
DBG(10, "get_params: bytes_per_line=%d, pixels_per_line=%d, lines=%d\n" DBG(10, "get_params: bytes_per_line=%d, pixels_per_line=%d, lines=%d\n"
"max_res=%d, res=%d, max_height=%d, total_lines=%d\n" "max_res=%d, res=%d, max_height=%d, br_y=%d, tl_y=%d, "
"br_y=%d, tl_y=%d, mm_per_in=%f\n", "mm_per_in=%f\n",
params->bytes_per_line, params->pixels_per_line, params->lines, params->bytes_per_line, params->pixels_per_line, params->lines,
max_res, res, max_height, total_lines, max_res, res, max_height, cs->vals[OPT_BR_Y],
cs->vals[OPT_BR_Y], cs->vals[OPT_TL_Y], MM_PER_IN); cs->vals[OPT_TL_Y], MM_PER_IN);
/* FIXME: Do we need to account for the scanner's max buffer here? */
DBG(2, "<< sane_get_parameters\n"); DBG(2, "<< sane_get_parameters\n");
return SANE_STATUS_GOOD; return SANE_STATUS_GOOD;
@ -1133,7 +1110,7 @@ sane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp)
/* feed some more data in until we've run out - don't care /* feed some more data in until we've run out - don't care
* whether or not we _think_ the scanner is scanning now, * whether or not we _think_ the scanner is scanning now,
* because we may still have data left over to send */ * because we may still have data left over to send */
DBG(100, "sane_read: didn't send it all last time\n"); DBG(200, "sane_read: didn't send it all last time\n");
/* Now feed it some data from lbuf */ /* Now feed it some data from lbuf */
if (bytesleft <= (unsigned int)maxlen) if (bytesleft <= (unsigned int)maxlen)
@ -1248,7 +1225,7 @@ sane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp)
(cs->params.id_string)+8); (cs->params.id_string)+8);
DBG(10, "scan_params->: width=%d, height=%d, xoffset=%d, " DBG(10, "scan_params->: width=%d, height=%d, xoffset=%d, "
"yoffset=%d\n\txresolution=%d, yresolution=%d, " "yoffset=%d\n\txresolution=%d, yresolution=%d, "
"mode=%d\n\n", "mode=%d\n",
cs->scan.width, cs->scan.height, cs->scan.width, cs->scan.height,
cs->scan.xoffset, cs->scan.yoffset, cs->scan.xoffset, cs->scan.yoffset,
cs->scan.xresolution, cs->scan.yresolution, cs->scan.xresolution, cs->scan.yresolution,
@ -1256,10 +1233,12 @@ sane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp)
); );
DBG(10, "lines=%d\n",lines); DBG(10, "lines=%d\n",lines);
DBG(2, ">> read_segment(%p, %p, %p, %d)\n", DBG(2, ">> read_segment(%p, %p, %p, %d, %d, %d)\n",
&is, &(cs->params), &(cs->scan), lines); &is, &(cs->params), &(cs->scan), lines,
cs->cal_valid, cs->scan.height - cs->lines_scanned);
tmp = sanei_canon_pp_read_segment(&is, &(cs->params), tmp = sanei_canon_pp_read_segment(&is, &(cs->params),
&(cs->scan), lines, cs->cal_valid); &(cs->scan), lines, cs->cal_valid,
cs->scan.height - cs->lines_scanned);
DBG(2, "<< %d read_segment\n", tmp); DBG(2, "<< %d read_segment\n", tmp);
if (tmp != 0) { if (tmp != 0) {
@ -1272,47 +1251,18 @@ sane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp)
cs->lines_scanned += lines; cs->lines_scanned += lines;
/* translate data out of buffer */ /* translate data out of buffer */
if (cs->vals[OPT_COLOUR_MODE] == 0)
{
/* fudge because simon's code is slack and returns greyscale as
* RGB data, just with the same stuff in R,G,B. */
DBG(10, "sane_read: Initialising FUDGE engine 1.0\n");
if (cs->vals[OPT_DEPTH] == 0)
{
/* 8bpp */
for(i = 0; i < bytes * 3; i += 3)
{
*((char *)lbuf + i/3) =
*((char *)(is->image_data) + (i*2));
}
}
else
{
/* 16bpp */
for(i = 0; i < (bytes/2) * 3; i += 3)
{
/* Convert bigendian data to the local system */
*((short *)lbuf + i/3) = MAKE_SHORT(
*((char *)(is->image_data)
+ (i*2)),
*((char *)(is->image_data)
+ (i*2)+1)
);
}
}
}
else
{
if (cs->vals[OPT_DEPTH] == 0) if (cs->vals[OPT_DEPTH] == 0)
{ {
/* 8bpp */ /* 8bpp */
for(i = 0; i < bytes; i++) for(i = 0; i < bytes; i++)
{ {
charptr = lbuf + i; charptr = lbuf + i;
if (cs->vals[OPT_COLOUR_MODE])
{
if (i % 3 == 0) charptr += 2; if (i % 3 == 0) charptr += 2;
if (i % 3 == 2) charptr -= 2; if (i % 3 == 2) charptr -= 2;
*(charptr) = }
*((char *)(is->image_data) + (i*2)); *charptr = *((char *)(is->image_data) + (i*2));
} }
} }
else else
@ -1321,17 +1271,22 @@ sane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp)
for(i = 0; i < (bytes/2); i++) for(i = 0; i < (bytes/2); i++)
{ {
shortptr = ((short *)lbuf + i); shortptr = ((short *)lbuf + i);
if (cs->vals[OPT_COLOUR_MODE])
{
if (i % 3 == 0) shortptr += 2; if (i % 3 == 0) shortptr += 2;
if (i % 3 == 2) shortptr -= 2; if (i % 3 == 2) shortptr -= 2;
}
*shortptr = MAKE_SHORT( *shortptr = MAKE_SHORT(
*((char *)(is->image_data) + *((char *)(is->image_data) + (i*2)),
(i*2)), *((char *)(is->image_data) + (i*2)+1)
*((char *)(is->image_data) + );
(i*2)+1));
}
} }
} }
/* Free data structures allocated in read_segment */
free(is->image_data);
free(is);
/* Now feed it some data from lbuf */ /* Now feed it some data from lbuf */
if (bytes <= (unsigned int)maxlen) if (bytes <= (unsigned int)maxlen)
{ {
@ -1577,15 +1532,15 @@ static SANE_Status init_device(struct parport *pp)
DBG(2, ">> init_device\n"); DBG(2, ">> init_device\n");
cs = malloc (sizeof (CANONP_Scanner)); cs = malloc(sizeof(*cs));
if (cs == NULL) if (cs == NULL)
{ {
return SANE_STATUS_NO_MEM; return SANE_STATUS_NO_MEM;
} }
memset (cs, 0, sizeof (CANONP_Scanner)); memset(cs, 0, sizeof(*cs));
#if 0 #if 0
if ((cs->params.port = malloc(sizeof(*pp))) == NULL) if ((cs->params.port = malloc(sizeof(*(cs->params.port)))) == NULL)
return SANE_STATUS_NO_MEM; return SANE_STATUS_NO_MEM;
memcpy(cs->params.port, pp, sizeof(*pp)); memcpy(cs->params.port, pp, sizeof(*pp));
@ -1839,7 +1794,7 @@ static SANE_Status fix_weights_file(CANONP_Scanner *cs)
cs->weights_file = tmp; cs->weights_file = tmp;
} }
if ((f_stat = malloc(sizeof(struct stat))) == NULL) if ((f_stat = malloc(sizeof(*f_stat))) == NULL)
return SANE_STATUS_NO_MEM; return SANE_STATUS_NO_MEM;
if(stat(cs->weights_file, f_stat)) if(stat(cs->weights_file, f_stat))
@ -1859,8 +1814,6 @@ static SANE_Status fix_weights_file(CANONP_Scanner *cs)
} }
else else
{ {
free(f_stat);
f_stat = NULL;
/* No error returned.. Check read/writability */ /* No error returned.. Check read/writability */
i = open(cs->weights_file, O_RDWR | O_APPEND); i = open(cs->weights_file, O_RDWR | O_APPEND);
@ -1896,6 +1849,9 @@ static SANE_Status fix_weights_file(CANONP_Scanner *cs)
} }
} }
/* cleanup */
free(f_stat);
return SANE_STATUS_GOOD; return SANE_STATUS_GOOD;
} }

Wyświetl plik

@ -42,9 +42,9 @@ This backend expects device names of the form presented by libieee1284. These n
On Linux 2.4 kernels this will be of the form On Linux 2.4 kernels this will be of the form
.I "parport0" .I "parport0"
or older (2.2) kernels may produce names like or older (2.2 and before) kernels may produce names like
.IR "0x378" .IR "0x378"
or simply (the base address of your port) or simply
.IR "0" .IR "0"
depending on your module configuration. Check the contents of depending on your module configuration. Check the contents of
.I /proc/parport .I /proc/parport
@ -144,10 +144,10 @@ anti-aliasing filter. Again, it seems to be implemeneted entirely in
software, so GIMP is your best bet for now. software, so GIMP is your best bet for now.
.TP .TP
.B Gamma Tables .B Gamma Tables
This is under investigation, but for now only a simple gamma profile will be This is under investigation, but for now only a simple gamma profile (ie: the
loaded. one returned during calibration) will be loaded.
.PP .PP
.B Other Notes .B Communication Problems
.PP .PP
ECP mode in libieee1284 doesn't always work properly, even with new hardware. ECP mode in libieee1284 doesn't always work properly, even with new hardware.
We beleive that this is a ppdev problem. If you change the configuration file We beleive that this is a ppdev problem. If you change the configuration file
@ -175,6 +175,14 @@ movement for a start/stop event is greater than 1/600 inches. I've never
tried the windows driver so I'm not sure how (or if) it works around tried the windows driver so I'm not sure how (or if) it works around
this problem, but as we don't know how to rewind the scanner head to do these this problem, but as we don't know how to rewind the scanner head to do these
bits again, there's currently no nice way to deal with the problem. bits again, there's currently no nice way to deal with the problem.
.PP
.B Greyscale Scans
.PP
Be aware that the scanner uses the green LEDs to read greyscale scans,
meaning green coloured things will appear lighter than normal, and red
and blue coloured items will appear darker than normal. For high-accuracy
greyscale scans of colour items, it's best just to scan in colour and convert
to greyscale in graphics software such as the GIMP.
.SH "SEE ALSO" .SH "SEE ALSO"
sane(7), sane-dll(5) sane(7), sane-dll(5)