Changes for ADF simplex and duplex scan, MP970 4800 dpi and TPU scan.

merge-requests/1/head
Nicolas Martin 2008-10-05 20:42:19 +00:00
rodzic 7fa6ae708c
commit 1aa1677ef2
8 zmienionych plików z 829 dodań i 681 usunięć

Wyświetl plik

@ -1,3 +1,20 @@
2008-10-04 Nicolas Martin <nicols-guest at users.alioth.debian.org>
* backend/pixma.c, backend/pixma.h, backend/pixma_common.c,
backend/pixma_io_sanei.c, backend/pixma_mp150.c,
doc/sane-pixma.man, doc/description/pixma.desc:
MP970 scanning improvements, up to 4800 dpi. On the way soon,
network BJNP protocol designed by Louis Lagendijk to be added to CVS.
MX7600 reported to work fine with the backend.
ADF scanning:
- improved for latest PIXMAs like MX850, MX310.
- bug fix in Sane_start, when scanning several pages with ADF.
ADF DUPLEX scanning:
- new code for ADF Duplex, (to be tested) based on a MX850 Snoop. Changes
might fit also MP830 (To be confirmed).
TPU scanning:
- MP970 TPU scanning: Protocol works, get scanned TPU images with 48 bits
to 24 bits conversion, full 48 bit version yet to be debugged.
2008-10-03 m. allan noah <kitno455 a t gmail d o t com>
* backend/epjitsu.[ch]: backend v17:
- increase scan height ~1/2 inch due to head offset

Wyświetl plik

@ -582,6 +582,7 @@ calc_scan_param (pixma_sane_t * ss, pixma_scan_param_t * sp)
sp->gamma_table = (OVAL (opt_custom_gamma).b) ? ss->gamma_table : NULL;
sp->source = ss->source_map[OVAL (opt_source).w];
sp->adf_pageid = ss->page_count;
error = pixma_check_scan_param (ss->s, sp);
if (error < 0)
@ -646,7 +647,7 @@ init_option_descriptors (pixma_sane_t * ss)
ss->source_map[i] = PIXMA_SOURCE_ADFDUP;
i++;
}
#if 0
#if 1
if (cfg->cap & PIXMA_CAP_TPU)
{
ss->source_list[i] = SANE_I18N ("Transparency Unit");
@ -1220,9 +1221,20 @@ sane_start (SANE_Handle h)
if (!ss)
return SANE_STATUS_INVAL;
if (!ss->idle && ss->scanning)
{
PDBG (pixma_dbg (3, "Warning in Sane_start: !idle && scanning. idle=%d, ss->scanning=%d\n",
ss->idle, ss->scanning));
if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP)
return SANE_STATUS_INVAL;
}
ss->cancel = SANE_FALSE;
if (ss->idle ||
ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_FLATBED ||
ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU)
ss->page_count = 0; /* start from idle state or scan from flatbed or TPU */
else
ss->page_count++;
if (calc_scan_param (ss, &ss->sp) < 0)
return SANE_STATUS_INVAL;
ss->image_bytes_read = 0;
@ -1233,12 +1245,6 @@ sane_start (SANE_Handle h)
{
ss->output_line_size = ss->sp.w * ss->sp.channels * (ss->sp.depth / 8);
ss->byte_pos_in_line = 0;
if (ss->idle ||
ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_FLATBED ||
ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU)
ss->page_count = 0; /* start from idle state or scan from flatbed or TPU */
else
ss->page_count++;
ss->last_read_status = SANE_STATUS_GOOD;
ss->scanning = SANE_TRUE;
ss->idle = SANE_FALSE;
@ -1296,9 +1302,7 @@ sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len)
n = ss->sp.line_size - ss->byte_pos_in_line;
if (n > (int) sizeof (temp))
{
PDBG (pixma_dbg (3,
"Inefficient skip buffer. Should be %d\n",
n));
PDBG (pixma_dbg (3, "Inefficient skip buffer. Should be %d\n", n));
n = sizeof (temp);
}
status = read_image (ss, temp, n, &n);

Wyświetl plik

@ -266,6 +266,9 @@ struct pixma_scan_param_t
/** \see #pixma_paper_source_t */
pixma_paper_source_t source;
/** The current page # in the same ADF scan session, 0 in non ADF */
unsigned adf_pageid;
};
/** PIXMA model information */

Wyświetl plik

@ -644,7 +644,6 @@ pixma_read_image (pixma_t * s, void *buf, unsigned len)
if (result == 0)
{ /* end of image? */
s->ops->finish_scan (s);
#ifndef NDEBUG
if (s->cur_image_size != s->param->image_size)
{
pixma_dbg (1, "WARNING:image size mismatches\n");
@ -659,7 +658,6 @@ pixma_read_image (pixma_t * s, void *buf, unsigned len)
"BUG:received data not multiple of line_size\n");
}
}
#endif /* !NDEBUG */
if (s->cur_image_size < s->param->image_size)
{
s->underrun = 1;

Wyświetl plik

@ -57,6 +57,19 @@
#include "pixma_common.h"
#include "pixma_io.h"
/* Some macro code to enhance readability */
#define RET_IF_ERR(x) do { \
if ((error = (x)) < 0) \
return error; \
} while(0)
#define WAIT_INTERRUPT(x) do { \
error = handle_interrupt (s, x); \
if (s->cancel) \
return PIXMA_ECANCELED; \
if (error != PIXMA_ECANCELED && error < 0) \
return error; \
} while(0)
#ifdef __GNUC__
# define UNUSED(v) (void) v
@ -136,6 +149,8 @@ enum mp150_cmd_t
cmd_scan_param_3 = 0xd820,
cmd_scan_start_3 = 0xd920,
cmd_status_3 = 0xda20,
cmd_get_tpu_info_3 = 0xf520,
cmd_set_tpu_info_3 = 0xea20,
cmd_e920 = 0xe920 /* seen in MP800 */
};
@ -153,10 +168,12 @@ typedef struct mp150_t
uint8_t *data_left_ofs;
unsigned data_left_len;
int shift[3];
unsigned lines_shift;
unsigned color_shift;
unsigned stripe_shift;
uint8_t tpu_datalen;
uint8_t tpu_data[0x40];
} mp150_t;
/*
STAT: 0x0606 = ok,
0x1515 = failed (PIXMA_ECANCELED),
@ -212,11 +229,58 @@ typedef struct mp150_t
static void mp150_finish_scan (pixma_t * s);
static int
is_scanning_from_adf (pixma_t * s)
{
return (s->param->source == PIXMA_SOURCE_ADF
|| s->param->source == PIXMA_SOURCE_ADFDUP);
}
static int
is_scanning_from_adfdup (pixma_t * s)
{
return (s->param->source == PIXMA_SOURCE_ADFDUP);
}
static int
is_scanning_from_tpu (pixma_t * s)
{
return (s->param->source == PIXMA_SOURCE_TPU);
}
static void
new_cmd_tpu_msg (pixma_t *s, pixma_cmdbuf_t * cb, uint16_t cmd)
{
pixma_newcmd (cb, cmd, 0, 0);
cb->buf[3] = (is_scanning_from_tpu (s)) ? 0x01 : 0x00;
}
static int
start_session (pixma_t * s)
{
mp150_t *mp = (mp150_t *) s->subdriver;
new_cmd_tpu_msg (s, &mp->cb, cmd_start_session);
return pixma_exec (s, &mp->cb);
}
static int
start_scan_3 (pixma_t * s)
{
mp150_t *mp = (mp150_t *) s->subdriver;
return pixma_exec_short_cmd (s, &mp->cb, cmd_scan_start_3);
new_cmd_tpu_msg (s, &mp->cb, cmd_scan_start_3);
return pixma_exec (s, &mp->cb);
}
static int
send_cmd_start_calibrate_ccd_3 (pixma_t * s)
{
mp150_t *mp = (mp150_t *) s->subdriver;
pixma_newcmd (&mp->cb, cmd_start_calibrate_ccd_3, 0, 0);
mp->cb.buf[3] = 0x01;
return pixma_exec (s, &mp->cb);
}
static int
@ -241,6 +305,10 @@ static int
has_paper (pixma_t * s)
{
mp150_t *mp = (mp150_t *) s->subdriver;
if (is_scanning_from_adfdup (s))
return (mp->current_status[1] == 0 || mp->current_status[2] == 0);
else
return (mp->current_status[1] == 0);
}
@ -265,20 +333,6 @@ send_cmd_e920 (pixma_t * s)
return pixma_exec_short_cmd (s, &mp->cb, cmd_e920);
}
static int
send_cmd_start_calibrate_ccd_3 (pixma_t * s)
{
mp150_t *mp = (mp150_t *) s->subdriver;
return pixma_exec_short_cmd (s, &mp->cb, cmd_start_calibrate_ccd_3);
}
static int
start_session (pixma_t * s)
{
mp150_t *mp = (mp150_t *) s->subdriver;
return pixma_exec_short_cmd (s, &mp->cb, cmd_start_session);
}
static int
select_source (pixma_t * s)
{
@ -325,6 +379,32 @@ select_source (pixma_t * s)
return pixma_exec (s, &mp->cb);
}
static int
send_get_tpu_info_3 (pixma_t * s)
{
mp150_t *mp = (mp150_t *) s->subdriver;
uint8_t *data;
int error;
data = pixma_newcmd (&mp->cb, cmd_get_tpu_info_3, 0, 0x34);
RET_IF_ERR (pixma_exec (s, &mp->cb));
memcpy (mp->tpu_data, data, 0x34);
return error;
}
static int
send_set_tpu_info_3 (pixma_t * s)
{
mp150_t *mp = (mp150_t *) s->subdriver;
uint8_t *data;
if (mp->tpu_datalen == 0)
return 0;
data = pixma_newcmd (&mp->cb, cmd_set_tpu_info_3, 0x34, 0);
memcpy (data, mp->tpu_data, 0x34);
return pixma_exec (s, &mp->cb);
}
static int
send_gamma_table (pixma_t * s)
{
@ -414,36 +494,35 @@ get_cis_ccd_line_size (pixma_t * s)
return (s->param->line_size * ((is_ccd_grayscale (s)) ? 3 : 1));
}
static int
is_scanning_from_adf (pixma_t * s)
{
return (s->param->source == PIXMA_SOURCE_ADF
|| s->param->source == PIXMA_SOURCE_ADFDUP);
}
static unsigned
calc_shifting (pixma_t * s)
{
mp150_t *mp = (mp150_t *) s->subdriver;
unsigned base_shift;
/* Default: no shift to apply (e.g. CIS sensord) */
mp->stripe_shift = 0;
mp->color_shift = 0;
/* If color plane shift (CCD devices), how many pixels shift */
switch (s->cfg->pid)
{
case MP970_PID: /* MP970 at 4800 dpi */
if (s->param->xdpi == 4800)
mp->stripe_shift = 3;
/* fall through */
case MP800_PID:
case MP810_PID:
case MP830_PID:
case MP960_PID:
case MP970_PID:
mp->lines_shift = 0;
if (s->param->ydpi > 75)
mp->lines_shift = s->param->ydpi / 50;
mp->color_shift = s->param->ydpi / 50;
break;
default: /* all CIS devices */
mp->lines_shift = 0;
break;
}
base_shift = get_cis_ccd_line_size (s) * mp->lines_shift;
base_shift = get_cis_ccd_line_size (s) * mp->color_shift;
/* If color plane shift, how to apply the shift */
switch (s->cfg->pid)
@ -463,7 +542,7 @@ calc_shifting (pixma_t * s)
mp->shift[1] = base_shift;
mp->shift[2] = 0;
}
return mp->lines_shift;
return (2 * mp->color_shift + mp->stripe_shift);
}
static int
@ -472,7 +551,7 @@ send_scan_param (pixma_t * s)
mp150_t *mp = (mp150_t *) s->subdriver;
uint8_t *data;
unsigned raw_width = calc_raw_width (mp, s->param);
unsigned h = MIN (s->param->h + 2 * calc_shifting (s),
unsigned h = MIN (s->param->h + calc_shifting (s),
s->cfg->height * s->param->ydpi / 75);
if (mp->generation <= 2)
@ -494,9 +573,20 @@ send_scan_param (pixma_t * s)
else
{
data = pixma_newcmd (&mp->cb, cmd_scan_param_3, 0x38, 0);
data[0x00] = (s->param->source == PIXMA_SOURCE_ADF) ? 0x02 : 0x01;
data[0x00] = (is_scanning_from_adf (s)) ? 0x02 : 0x01;
data[0x01] = 0x01;
if (is_scanning_from_tpu (s))
{
data[0x00] = 0x04;
data[0x01] = 0x02;
data[0x1e] = 0x02;
}
data[0x02] = 0x01;
if (is_scanning_from_adfdup (s))
{
data[0x02] = 0x03;
data[0x03] = 0x03;
}
data[0x05] = 0x01; /* This one also seen at 0. Don't know yet what's used for */
pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x08);
pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x0a);
@ -505,7 +595,9 @@ send_scan_param (pixma_t * s)
pixma_set_be32 (raw_width, data + 0x14);
pixma_set_be32 (h, data + 0x18);
data[0x1c] = ((s->param->channels != 1) || is_ccd_grayscale (s)) ? 0x08 : 0x04;
data[0x1d] = s->param->depth * ((is_ccd_grayscale (s)) ? 3 : s->param->channels); /* bits per pixel */
data[0x1d] = s->param->depth *
((is_ccd_grayscale (s)) ? 3 : s->param->channels) *
((is_scanning_from_tpu (s)) ? 2 : 1); /* bits per pixel */
data[0x1f] = 0x01;
data[0x20] = 0xff;
data[0x21] = 0x81;
@ -525,32 +617,8 @@ query_status_3 (pixma_t * s)
status_len = 8;
data = pixma_newcmd (&mp->cb, cmd_status_3, 0, status_len);
error = pixma_exec (s, &mp->cb);
if (error >= 0)
{
RET_IF_ERR (pixma_exec (s, &mp->cb));
memcpy (mp->current_status, data, status_len);
}
return error;
}
static int
init_ccd_3 (pixma_t * s)
{
mp150_t *mp = (mp150_t *) s->subdriver;
uint8_t *data;
int error, status_len;
status_len = 8;
error = send_cmd_start_calibrate_ccd_3 (s);
if (error >= 0)
{
data = pixma_newcmd (&mp->cb, cmd_end_calibrate_ccd_3, 0, status_len);
error = pixma_exec (s, &mp->cb);
if (error >= 0)
{
memcpy (mp->current_status, data, status_len);
}
}
return error;
}
@ -563,13 +631,10 @@ query_status (pixma_t * s)
status_len = (mp->generation == 1) ? 12 : 16;
data = pixma_newcmd (&mp->cb, cmd_status, 0, status_len);
error = pixma_exec (s, &mp->cb);
if (error >= 0)
{
RET_IF_ERR (pixma_exec (s, &mp->cb));
memcpy (mp->current_status, data, status_len);
PDBG (pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u busy=%u\n",
data[1], data[8], data[7], data[9]));
}
return error;
}
@ -625,17 +690,14 @@ read_image_block (pixma_t * s, uint8_t * header, uint8_t * data)
if (mp->cb.reslen == 512)
{
error = pixma_read (s->io, data, IMAGE_BLOCK_SIZE - 512 + hlen);
if (error < 0)
return error;
RET_IF_ERR (error);
datalen += error;
}
}
mp->state = state_scanning;
mp->cb.expected_reslen = 0;
error = pixma_check_result (&mp->cb);
if (error < 0)
return error;
RET_IF_ERR (pixma_check_result (&mp->cb));
if (mp->cb.reslen < hlen)
return PIXMA_EPROTO;
return datalen;
@ -650,10 +712,9 @@ read_error_info (pixma_t * s, void *buf, unsigned size)
int error;
data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len);
error = pixma_exec (s, &mp->cb);
if (error >= 0 && buf)
RET_IF_ERR (pixma_exec (s, &mp->cb));
if (buf && len < size)
{
if (len < size)
size = len;
/* NOTE: I've absolutely no idea what the returned data mean. */
memcpy (buf, data, size);
@ -704,24 +765,45 @@ handle_interrupt (pixma_t * s, int timeout)
return 1;
}
static int
init_ccd_lamp_3 (pixma_t * s)
{
mp150_t *mp = (mp150_t *) s->subdriver;
uint8_t *data;
int error, status_len, tmo;
status_len = 8;
RET_IF_ERR (query_status (s));
RET_IF_ERR (query_status (s));
RET_IF_ERR (send_cmd_start_calibrate_ccd_3 (s));
RET_IF_ERR (query_status (s));
tmo = 20; /* like Windows driver, CCD lamp adjustment */
while (--tmo >= 0)
{
data = pixma_newcmd (&mp->cb, cmd_end_calibrate_ccd_3, 0, status_len);
RET_IF_ERR (pixma_exec (s, &mp->cb));
memcpy (mp->current_status, data, status_len);
PDBG (pixma_dbg (3, "Lamp status: %u , timeout in: %u\n", data[0], tmo));
if (mp->current_status[0] == 3 || !is_scanning_from_tpu (s))
break;
WAIT_INTERRUPT (1000);
}
return error;
}
static int
wait_until_ready (pixma_t * s)
{
mp150_t *mp = (mp150_t *) s->subdriver;
int error, tmo = 60;
error = (mp->generation == 3) ? query_status_3 (s) : query_status (s);
if (error < 0)
return error;
RET_IF_ERR ((mp->generation == 3) ? query_status_3 (s)
: query_status (s));
while (!is_calibrated (s))
{
error = handle_interrupt (s, 1000);
if (mp->generation == 3)
error = query_status_3 (s);
if (s->cancel)
return PIXMA_ECANCELED;
if (error != PIXMA_ECANCELED && error < 0)
return error;
RET_IF_ERR (query_status_3 (s));
WAIT_INTERRUPT (1000);
if (--tmo == 0)
{
PDBG (pixma_dbg (1, "WARNING:Timed out in wait_until_ready()\n"));
@ -731,14 +813,146 @@ wait_until_ready (pixma_t * s)
#if 0
/* If we use sanei_usb_*, we sometimes lose interrupts! So poll the
* status here. */
error = query_status (s);
if (error < 0)
return error;
RET_IF_ERR (query_status (s));
#endif
}
return 0;
}
static uint8_t *
shift_colors (uint8_t * dptr, uint8_t * sptr,
unsigned w, unsigned dpi, unsigned pid,
int * colshft, unsigned strshft)
{
unsigned i, sr, sg, sb, st;
sr = colshft[0]; sg = colshft[1]; sb = colshft[2];
for (i = 0; i < w; i++)
{
/* MP970 at 4800 dpi exception stripes shift */
st = (pid == MP970_PID && dpi == 4800 && (i % 2) == 0) ? strshft : 0;
*sptr++ = *(dptr++ + sr + st);
*sptr++ = *(dptr++ + sg + st);
*sptr++ = *(dptr++ + sb + st);
}
return dptr;
}
static uint8_t *
rgb_to_gray (uint8_t * gptr, uint8_t * sptr, unsigned w)
{
unsigned i, g;
for (i = 0; i < w; i++)
{
g = *sptr++;
g += *sptr++;
*gptr++ = (*sptr++ + g) / 3;
}
return gptr;
}
static void
reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, unsigned n,
unsigned m, unsigned w, unsigned line_size)
{
unsigned i;
for (i = 0; i < w; i++)
{
memcpy (linebuf + c * (n * (i % m) + i / m), sptr + c * i, c);
}
memcpy (sptr, linebuf, line_size);
}
static void
mp970_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c,
unsigned w, unsigned line_size)
{
unsigned i, i8;
for (i = 0; i < w; i++)
{
i8 = i % 8;
memcpy (linebuf + c * (i + i8 - ((i8 > 3) ? 7 : 0)), sptr + c * i, c);
}
memcpy (sptr, linebuf, line_size);
}
static unsigned
pack_48_24_bpc (uint8_t * sptr, unsigned n)
{
unsigned i;
uint8_t *cptr;
cptr = sptr;
if (n % 2 != 0)
PDBG (pixma_dbg (3, "Warning: Odd number of bytes received, misaligned image.\n"));
for (i = 0; i < n; i += 2)
{
sptr++;
*cptr++ = *sptr++;
}
return (n / 2);
}
/* This function deals both with PIXMA CCD sensors producing shifted color
* planes images, Grayscale CCD scan and Generation 3 high dpi images.
* Each complete line in mp->imgbuf is processed for shifting CCD sensor
* color planes, reordering pixels above 600 dpi for Generation 3, and
* converting to Grayscale for CCD sensors. */
static unsigned
post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib)
{
mp150_t *mp = (mp150_t *) s->subdriver;
unsigned c, lines, i, line_size, n, m;
uint8_t *sptr, *dptr, *gptr;
c = (is_ccd_grayscale (s)) ? 3 : s->param->channels;
if (mp->generation == 3)
n = s->param->xdpi / 600;
else /* FIXME: maybe need different values for CIS and CCD sensors */
n = s->param->xdpi / 2400;
if (s->cfg->pid == MP970_PID)
n = MIN (n, 4);
m = (n > 0) ? s->param->w / n : 1;
sptr = dptr = gptr = mp->imgbuf;
line_size = get_cis_ccd_line_size (s);
lines = (mp->data_left_ofs - mp->imgbuf) / line_size;
if (lines > 2 * mp->color_shift + mp->stripe_shift)
{
lines -= 2 * mp->color_shift + mp->stripe_shift;
for (i = 0; i < lines; i++, sptr += line_size)
{
/* Color plane and stripes shift needed by e.g. CCD */
if (c == 3)
dptr = shift_colors (dptr, sptr,
s->param->w, s->param->xdpi, s->cfg->pid,
mp->shift, mp->stripe_shift);
/* special image format for *most* devices at high dpi.
* MP220 is a gen3 exception */
if (s->cfg->pid != MP220_PID && n > 0)
reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->w, line_size);
/* MP970 specific reordering for 4800 dpi */
if (s->cfg->pid == MP970_PID && s->param->xdpi == 4800)
mp970_reorder_pixels (mp->linebuf, sptr, c, s->param->w, line_size);
/* Color to Grayscale convert for CCD sensor */
if (is_ccd_grayscale (s))
gptr = rgb_to_gray (gptr, sptr, s->param->w);
}
}
ib->rptr = mp->imgbuf;
ib->rend = (is_ccd_grayscale (s)) ? gptr : sptr;
return mp->data_left_ofs - sptr; /* # of non processed bytes */
}
static int
mp150_open (pixma_t * s)
{
@ -776,8 +990,13 @@ mp150_open (pixma_t * s)
if (s->cfg->pid == MP140_PID)
mp->generation = 2;
/* TPU info data setup */
mp->tpu_datalen = 0;
query_status (s);
handle_interrupt (s, 200);
if (mp->generation == 3 && has_ccd_sensor (s))
send_cmd_start_calibrate_ccd_3 (s);
return 0;
}
@ -798,25 +1017,24 @@ mp150_check_param (pixma_t * s, pixma_scan_param_t * sp)
mp150_t *mp = (mp150_t *) s->subdriver;
sp->depth = 8; /* MP150 only supports 8 bit per channel. */
/* if (mp->generation == 3 && sp->source == PIXMA_SOURCE_TPU)
sp->depth = 16; */ /* TPU in 16 bits mode */
if (mp->generation >= 2)
{
/* mod 32 and expansion of the X scan limits */
sp->w += (sp->x) % 32;
sp->w = calc_raw_width (mp, sp);
sp->x = ALIGN_INF (sp->x, 32);
/* FIXME: TBC, if all gen2 and gen3 devices do not need
* modulo 32 alignment on Y axis. If needed, uncomment next 2 lines */
/* sp->h += (sp->y) % 32;
sp->y = ALIGN_INF (sp->y, 32);*/
}
sp->line_size = calc_raw_width (mp, sp) * sp->channels;
sp->line_size = calc_raw_width (mp, sp) * sp->channels * (sp->depth / 8);
return 0;
}
static int
mp150_scan (pixma_t * s)
{
int error = 0, tmo;
int error = 0, tmo, i;
mp150_t *mp = (mp150_t *) s->subdriver;
if (mp->state != state_idle)
@ -835,11 +1053,7 @@ mp150_scan (pixma_t * s)
tmo = 10;
while (!has_paper (s) && --tmo >= 0)
{
error = handle_interrupt (s, 1000);
if (s->cancel)
return PIXMA_ECANCELED;
if (error != PIXMA_ECANCELED && error < 0)
return error;
WAIT_INTERRUPT (1000);
PDBG (pixma_dbg
(2, "No paper in ADF. Timed out in %d sec.\n", tmo));
}
@ -847,40 +1061,36 @@ mp150_scan (pixma_t * s)
return PIXMA_ENO_PAPER;
}
if (has_ccd_sensor (s))
if (has_ccd_sensor (s) && (mp->generation <= 2))
{
error = (mp->generation <= 2) ? send_cmd_e920 (s)
: send_cmd_start_calibrate_ccd_3 (s);
error = send_cmd_e920 (s);
switch (error)
{
case PIXMA_ECANCELED:
case PIXMA_EBUSY:
PDBG (pixma_dbg
(2, "cmd e920 or d520 returned %s\n", pixma_strerror (error)));
PDBG (pixma_dbg (2, "cmd e920 or d520 returned %s\n",
pixma_strerror (error)));
/* fall through */
case 0:
query_status (s);
break;
default:
PDBG (pixma_dbg
(1, "WARNING:cmd e920 or d520 failed %s\n", pixma_strerror (error)));
PDBG (pixma_dbg (1, "WARNING:cmd e920 or d520 failed %s\n",
pixma_strerror (error)));
return error;
}
tmo = 3; /* like Windows driver, CCD calibration ? */
while (--tmo >= 0)
{
error = handle_interrupt (s, 1000);
if (s->cancel)
return PIXMA_ECANCELED;
if (error != PIXMA_ECANCELED && error < 0)
return error;
PDBG (pixma_dbg
(2, "CCD Calibration ends in %d sec.\n", tmo));
WAIT_INTERRUPT (1000);
PDBG (pixma_dbg (2, "CCD Calibration ends in %d sec.\n", tmo));
}
/* pixma_sleep(2000000); */
}
tmo = 10;
if (s->param->adf_pageid == 0 || mp->generation <= 2)
{
error = start_session (s);
while (error == PIXMA_EBUSY && --tmo >= 0)
{
@ -909,13 +1119,17 @@ mp150_scan (pixma_t * s)
if ((error >= 0) && (mp->generation <= 2))
error = select_source (s);
if ((error >= 0) && (mp->generation == 3) && has_ccd_sensor (s))
error = init_ccd_3 (s);
if (error >= 0)
error = send_gamma_table (s);
if ((error >= 0) && (mp->generation == 3))
error = send_gamma_table (s);
if ((error >= 0) && (mp->generation == 3))
error = init_ccd_lamp_3 (s);
if ((error >= 0) && !is_scanning_from_tpu (s))
for (i = (mp->generation == 3) ? 3 : 1 ; i > 0 && error >= 0; i--)
error = send_gamma_table (s);
else if (mp->generation == 3) /* FIXME: Does this apply also to gen2 ? */
error = send_set_tpu_info_3 (s);
}
else /* ADF pageid != 0 and gen3 */
pixma_sleep (1000000);
if ((error >= 0) || (mp->generation == 3))
mp->state = state_warmup;
if (error >= 0)
error = send_scan_param (s);
if ((error >= 0) && (mp->generation == 3))
@ -928,98 +1142,6 @@ mp150_scan (pixma_t * s)
return 0;
}
static uint8_t *
shift_colors (uint8_t * dptr, uint8_t * sptr, unsigned w, int sr, int sg, int sb)
{
unsigned i;
for (i = 0; i < w; i++)
{
*sptr++ = *(dptr++ + sr);
*sptr++ = *(dptr++ + sg);
*sptr++ = *(dptr++ + sb);
}
return dptr;
}
static uint8_t *
rgb_to_gray (uint8_t * gptr, uint8_t * sptr, unsigned w)
{
unsigned i, g;
for (i = 0; i < w; i++)
{
g = *sptr++;
g += *sptr++;
*gptr++ = (*sptr++ + g) / 3;
}
return gptr;
}
static void
reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, unsigned n,
unsigned m, unsigned w, unsigned line_size)
{
unsigned i;
for (i = 0; i < w; i++)
{
memcpy (linebuf + c * (n * (i % m) + i / m), sptr + c * i, c);
}
memcpy (sptr, linebuf, line_size);
}
/* This function deals both with PIXMA CCD sensors producing shifted color
* planes images, Grayscale CCD scan and Generation 3 high dpi images.
* Each complete line in mp->imgbuf is processed for shifting CCD sensor
* color planes, reordering pixels above 600 dpi for Generation 3, and
* converting to Grayscale for CCD sensors. */
static unsigned
post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib)
{
mp150_t *mp = (mp150_t *) s->subdriver;
unsigned c, lines, i, line_size, n, m;
uint8_t *sptr, *dptr, *gptr;
c = (is_ccd_grayscale (s)) ? 3 : s->param->channels;
if (mp->generation == 3)
n = s->param->xdpi / 600;
else /* FIXME: maybe need different values for CIS and CCD sensors */
n = s->param->xdpi / 2400;
if (s->cfg->pid == MP970_PID)
n = MIN (n, 4);
m = (n > 0) ? s->param->w / n : 1;
sptr = dptr = gptr = mp->imgbuf;
line_size = get_cis_ccd_line_size (s);
lines = (mp->data_left_ofs - mp->imgbuf) / line_size;
if (lines > 2 * mp->lines_shift)
{
lines -= 2 * mp->lines_shift;
for (i = 0; i < lines; i++, sptr += line_size)
{
/* Color plane shift needed by e.g. CCD */
if (c == 3)
dptr = shift_colors (dptr, sptr, s->param->w,
mp->shift[0], mp->shift[1], mp->shift[2]);
/* special image format for *most* devices at high dpi.
* MP220 is a gen3 exception */
if (s->cfg->pid != MP220_PID && n > 0)
reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->w, line_size);
/* Color to Grayscale convert for CCD sensor */
if (is_ccd_grayscale (s))
gptr = rgb_to_gray (gptr, sptr, s->param->w);
}
}
ib->rptr = mp->imgbuf;
ib->rend = (is_ccd_grayscale (s)) ? gptr : sptr;
return mp->data_left_ofs - sptr; /* # of non processed bytes */
}
static int
mp150_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib)
{
@ -1030,9 +1152,7 @@ mp150_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib)
if (mp->state == state_warmup)
{
error = wait_until_ready (s);
if (error < 0)
return error;
RET_IF_ERR (wait_until_ready (s));
pixma_sleep (1000000); /* No need to sleep, actually, but Window's driver
* sleep 1.5 sec. */
mp->state = state_scanning;
@ -1054,8 +1174,7 @@ mp150_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib)
if (s->cancel)
return PIXMA_ECANCELED;
if ((mp->last_block & 0x28) == 0x28)
{
/* end of image */
{ /* end of image */
mp->state = state_finished;
return 0;
}
@ -1082,11 +1201,15 @@ mp150_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib)
PASSERT (bytes_received == block_size);
if (block_size == 0)
{
/* no image data at this moment. */
{ /* no image data at this moment. */
pixma_sleep (10000);
}
/* In case of TPU, at 48 bits/col scan, pack the newly received data */
if (mp->generation == 3 && is_scanning_from_tpu (s))
bytes_received = pack_48_24_bpc (mp->imgbuf + mp->data_left_len, bytes_received);
/* Post-process the image data */
mp->data_left_ofs = mp->imgbuf + mp->data_left_len + bytes_received;
mp->data_left_len = post_process_image_data (s, ib);
mp->data_left_ofs -= mp->data_left_len;
@ -1109,17 +1232,20 @@ mp150_finish_scan (pixma_t * s)
/* fall through */
case state_scanning:
case state_warmup:
error = abort_session (s);
if (error < 0)
PDBG (pixma_dbg (1, "WARNING:abort_session() failed %d\n", error));
/* fall through */
case state_finished:
/* For gen3 TPU , send the get TPU info message */
if (mp->generation == 3 && is_scanning_from_tpu (s) && mp->tpu_datalen == 0)
send_get_tpu_info_3 (s);
/* FIXME: to process several pages ADF scan, must not send
* abort_session and start_session between pages (last_block=0x28)
* if (mp->last_block != 0x28 || !is_scanning_from_adf(s)) */
if (mp->last_block != 0x38)
abort_session (s); /* FIXME: it probably doesn't work in duplex mode! */
if (mp->generation <= 2 || !is_scanning_from_adf (s) || mp->last_block == 0x38)
{
error = abort_session (s); /* FIXME: it probably doesn't work in duplex mode! */
if (error < 0)
PDBG (pixma_dbg (1, "WARNING:abort_session() failed %d\n", error));
mp->state = state_idle;
}
/* fall through */
case state_idle:
break;
@ -1141,9 +1267,7 @@ mp150_get_status (pixma_t * s, pixma_device_status_t * status)
{
int error;
error = query_status (s);
if (error < 0)
return error;
RET_IF_ERR (query_status (s));
status->hardware = PIXMA_HARDWARE_OK;
status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER;
status->cal =

Wyświetl plik

@ -158,7 +158,7 @@
:interface "USB"
:usbid "0x04a9" "0x1713"
:status :basic
:comment "Single-side ADF works but duplex doesn't work yet."
:comment "Single-side ADF works, Duplex ADF to be tested."
:model "PIXMA MP960"
:interface "USB"
@ -169,7 +169,7 @@
:interface "USB"
:usbid "0x04a9" "0x1726"
:status :good
:comment "All resolutions supported (up to 4800DPI)"
:comment "All resolutions supported (up to 4800DPI). TPU support currently experimental."
:model "SmartBase MP360"
:interface "USB"
@ -240,8 +240,8 @@
:model "PIXMA MX7600"
:interface "USB"
:usbid "0x04a9" "0x171c"
:status :untested
:comment "Generation 3 protocol? Testers needed!"
:status :good
:comment "Flatbed and ADF scan. All resolutions supported (up to 4800DPI)"
:model "imageCLASS MF5630"
:interface "USB"

Wyświetl plik

@ -18,7 +18,7 @@ PIXMA MP600, MP600R, MP610, MP710
.br
PIXMA MP800, MP800R, MP810, MP830, MP960, MP970
.br
PIXMA MX300, MX310, MX700
PIXMA MX300, MX310, MX700, MX850, MX7600
.br
MultiPASS MP700, PIXMA MP750 (no grayscale)
.br
@ -47,13 +47,13 @@ ImageCLASS MF3110, MF3240
ImageCLASS MF5630, MF5650, MF5730, MF5750, MF5770, MF8170c
.RE
.PP
The following models may use partly the same Pixma protocol as MPs listed
above, but may still need some work. They are declared in the backend as
experimental. Snoop logs are required to further investigate, please contact
the sane\-devel mailing list.
\#The following models may use partly the same Pixma protocol as MPs listed
\#above, but may still need some work. They are declared in the backend as
\#experimental. Snoop logs are required to further investigate, please contact
\#the sane\-devel mailing list.
.PP
.RS
PIXMA MX850
\#PIXMA MX850
.RE
.PP
The backend supports
@ -64,7 +64,9 @@ The backend supports
.br
* a custom gamma table and
.br
* automatic document feeder (only single side, duplex needs some work).
* Automatic Document Feeder (Duplex for some models).
.br
* Transparency Unit support is still experimental.
.PP
The device name is in the form pixma:xxxxyyyy_zzzzz
where x, y and z are vendor ID, product ID and serial number respectively.