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> 2008-10-03 m. allan noah <kitno455 a t gmail d o t com>
* backend/epjitsu.[ch]: backend v17: * backend/epjitsu.[ch]: backend v17:
- increase scan height ~1/2 inch due to head offset - 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->gamma_table = (OVAL (opt_custom_gamma).b) ? ss->gamma_table : NULL;
sp->source = ss->source_map[OVAL (opt_source).w]; sp->source = ss->source_map[OVAL (opt_source).w];
sp->adf_pageid = ss->page_count;
error = pixma_check_scan_param (ss->s, sp); error = pixma_check_scan_param (ss->s, sp);
if (error < 0) if (error < 0)
@ -646,7 +647,7 @@ init_option_descriptors (pixma_sane_t * ss)
ss->source_map[i] = PIXMA_SOURCE_ADFDUP; ss->source_map[i] = PIXMA_SOURCE_ADFDUP;
i++; i++;
} }
#if 0 #if 1
if (cfg->cap & PIXMA_CAP_TPU) if (cfg->cap & PIXMA_CAP_TPU)
{ {
ss->source_list[i] = SANE_I18N ("Transparency Unit"); ss->source_list[i] = SANE_I18N ("Transparency Unit");
@ -1220,9 +1221,20 @@ sane_start (SANE_Handle h)
if (!ss) if (!ss)
return SANE_STATUS_INVAL; return SANE_STATUS_INVAL;
if (!ss->idle && ss->scanning) 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; return SANE_STATUS_INVAL;
}
ss->cancel = SANE_FALSE; 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) if (calc_scan_param (ss, &ss->sp) < 0)
return SANE_STATUS_INVAL; return SANE_STATUS_INVAL;
ss->image_bytes_read = 0; 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->output_line_size = ss->sp.w * ss->sp.channels * (ss->sp.depth / 8);
ss->byte_pos_in_line = 0; 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->last_read_status = SANE_STATUS_GOOD;
ss->scanning = SANE_TRUE; ss->scanning = SANE_TRUE;
ss->idle = SANE_FALSE; 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; n = ss->sp.line_size - ss->byte_pos_in_line;
if (n > (int) sizeof (temp)) if (n > (int) sizeof (temp))
{ {
PDBG (pixma_dbg (3, PDBG (pixma_dbg (3, "Inefficient skip buffer. Should be %d\n", n));
"Inefficient skip buffer. Should be %d\n",
n));
n = sizeof (temp); n = sizeof (temp);
} }
status = read_image (ss, temp, n, &n); status = read_image (ss, temp, n, &n);

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -57,6 +57,19 @@
#include "pixma_common.h" #include "pixma_common.h"
#include "pixma_io.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__ #ifdef __GNUC__
# define UNUSED(v) (void) v # define UNUSED(v) (void) v
@ -136,6 +149,8 @@ enum mp150_cmd_t
cmd_scan_param_3 = 0xd820, cmd_scan_param_3 = 0xd820,
cmd_scan_start_3 = 0xd920, cmd_scan_start_3 = 0xd920,
cmd_status_3 = 0xda20, cmd_status_3 = 0xda20,
cmd_get_tpu_info_3 = 0xf520,
cmd_set_tpu_info_3 = 0xea20,
cmd_e920 = 0xe920 /* seen in MP800 */ cmd_e920 = 0xe920 /* seen in MP800 */
}; };
@ -153,10 +168,12 @@ typedef struct mp150_t
uint8_t *data_left_ofs; uint8_t *data_left_ofs;
unsigned data_left_len; unsigned data_left_len;
int shift[3]; int shift[3];
unsigned lines_shift; unsigned color_shift;
unsigned stripe_shift;
uint8_t tpu_datalen;
uint8_t tpu_data[0x40];
} mp150_t; } mp150_t;
/* /*
STAT: 0x0606 = ok, STAT: 0x0606 = ok,
0x1515 = failed (PIXMA_ECANCELED), 0x1515 = failed (PIXMA_ECANCELED),
@ -212,11 +229,58 @@ typedef struct mp150_t
static void mp150_finish_scan (pixma_t * s); 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 static int
start_scan_3 (pixma_t * s) start_scan_3 (pixma_t * s)
{ {
mp150_t *mp = (mp150_t *) s->subdriver; 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 static int
@ -241,6 +305,10 @@ static int
has_paper (pixma_t * s) has_paper (pixma_t * s)
{ {
mp150_t *mp = (mp150_t *) s->subdriver; 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); 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); 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 static int
select_source (pixma_t * s) select_source (pixma_t * s)
{ {
@ -325,6 +379,32 @@ select_source (pixma_t * s)
return pixma_exec (s, &mp->cb); 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 static int
send_gamma_table (pixma_t * s) 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)); 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 static unsigned
calc_shifting (pixma_t * s) calc_shifting (pixma_t * s)
{ {
mp150_t *mp = (mp150_t *) s->subdriver; mp150_t *mp = (mp150_t *) s->subdriver;
unsigned base_shift; 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 */ /* If color plane shift (CCD devices), how many pixels shift */
switch (s->cfg->pid) 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 MP800_PID:
case MP810_PID: case MP810_PID:
case MP830_PID: case MP830_PID:
case MP960_PID: case MP960_PID:
case MP970_PID:
mp->lines_shift = 0;
if (s->param->ydpi > 75) if (s->param->ydpi > 75)
mp->lines_shift = s->param->ydpi / 50; mp->color_shift = s->param->ydpi / 50;
break; break;
default: /* all CIS devices */ 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 */ /* If color plane shift, how to apply the shift */
switch (s->cfg->pid) switch (s->cfg->pid)
@ -463,7 +542,7 @@ calc_shifting (pixma_t * s)
mp->shift[1] = base_shift; mp->shift[1] = base_shift;
mp->shift[2] = 0; mp->shift[2] = 0;
} }
return mp->lines_shift; return (2 * mp->color_shift + mp->stripe_shift);
} }
static int static int
@ -472,7 +551,7 @@ send_scan_param (pixma_t * s)
mp150_t *mp = (mp150_t *) s->subdriver; mp150_t *mp = (mp150_t *) s->subdriver;
uint8_t *data; uint8_t *data;
unsigned raw_width = calc_raw_width (mp, s->param); 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); s->cfg->height * s->param->ydpi / 75);
if (mp->generation <= 2) if (mp->generation <= 2)
@ -494,9 +573,20 @@ send_scan_param (pixma_t * s)
else else
{ {
data = pixma_newcmd (&mp->cb, cmd_scan_param_3, 0x38, 0); 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; data[0x01] = 0x01;
if (is_scanning_from_tpu (s))
{
data[0x00] = 0x04;
data[0x01] = 0x02;
data[0x1e] = 0x02;
}
data[0x02] = 0x01; 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 */ 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->xdpi | 0x8000, data + 0x08);
pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x0a); 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 (raw_width, data + 0x14);
pixma_set_be32 (h, data + 0x18); pixma_set_be32 (h, data + 0x18);
data[0x1c] = ((s->param->channels != 1) || is_ccd_grayscale (s)) ? 0x08 : 0x04; 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[0x1f] = 0x01;
data[0x20] = 0xff; data[0x20] = 0xff;
data[0x21] = 0x81; data[0x21] = 0x81;
@ -525,32 +617,8 @@ query_status_3 (pixma_t * s)
status_len = 8; status_len = 8;
data = pixma_newcmd (&mp->cb, cmd_status_3, 0, status_len); data = pixma_newcmd (&mp->cb, cmd_status_3, 0, status_len);
error = pixma_exec (s, &mp->cb); RET_IF_ERR (pixma_exec (s, &mp->cb));
if (error >= 0)
{
memcpy (mp->current_status, data, status_len); 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; return error;
} }
@ -563,13 +631,10 @@ query_status (pixma_t * s)
status_len = (mp->generation == 1) ? 12 : 16; status_len = (mp->generation == 1) ? 12 : 16;
data = pixma_newcmd (&mp->cb, cmd_status, 0, status_len); data = pixma_newcmd (&mp->cb, cmd_status, 0, status_len);
error = pixma_exec (s, &mp->cb); RET_IF_ERR (pixma_exec (s, &mp->cb));
if (error >= 0)
{
memcpy (mp->current_status, data, status_len); memcpy (mp->current_status, data, status_len);
PDBG (pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u busy=%u\n", PDBG (pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u busy=%u\n",
data[1], data[8], data[7], data[9])); data[1], data[8], data[7], data[9]));
}
return error; return error;
} }
@ -625,17 +690,14 @@ read_image_block (pixma_t * s, uint8_t * header, uint8_t * data)
if (mp->cb.reslen == 512) if (mp->cb.reslen == 512)
{ {
error = pixma_read (s->io, data, IMAGE_BLOCK_SIZE - 512 + hlen); error = pixma_read (s->io, data, IMAGE_BLOCK_SIZE - 512 + hlen);
if (error < 0) RET_IF_ERR (error);
return error;
datalen += error; datalen += error;
} }
} }
mp->state = state_scanning; mp->state = state_scanning;
mp->cb.expected_reslen = 0; mp->cb.expected_reslen = 0;
error = pixma_check_result (&mp->cb); RET_IF_ERR (pixma_check_result (&mp->cb));
if (error < 0)
return error;
if (mp->cb.reslen < hlen) if (mp->cb.reslen < hlen)
return PIXMA_EPROTO; return PIXMA_EPROTO;
return datalen; return datalen;
@ -650,10 +712,9 @@ read_error_info (pixma_t * s, void *buf, unsigned size)
int error; int error;
data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len); data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len);
error = pixma_exec (s, &mp->cb); RET_IF_ERR (pixma_exec (s, &mp->cb));
if (error >= 0 && buf) if (buf && len < size)
{ {
if (len < size)
size = len; size = len;
/* NOTE: I've absolutely no idea what the returned data mean. */ /* NOTE: I've absolutely no idea what the returned data mean. */
memcpy (buf, data, size); memcpy (buf, data, size);
@ -704,24 +765,45 @@ handle_interrupt (pixma_t * s, int timeout)
return 1; 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 static int
wait_until_ready (pixma_t * s) wait_until_ready (pixma_t * s)
{ {
mp150_t *mp = (mp150_t *) s->subdriver; mp150_t *mp = (mp150_t *) s->subdriver;
int error, tmo = 60; int error, tmo = 60;
error = (mp->generation == 3) ? query_status_3 (s) : query_status (s); RET_IF_ERR ((mp->generation == 3) ? query_status_3 (s)
if (error < 0) : query_status (s));
return error;
while (!is_calibrated (s)) while (!is_calibrated (s))
{ {
error = handle_interrupt (s, 1000);
if (mp->generation == 3) if (mp->generation == 3)
error = query_status_3 (s); RET_IF_ERR (query_status_3 (s));
if (s->cancel) WAIT_INTERRUPT (1000);
return PIXMA_ECANCELED;
if (error != PIXMA_ECANCELED && error < 0)
return error;
if (--tmo == 0) if (--tmo == 0)
{ {
PDBG (pixma_dbg (1, "WARNING:Timed out in wait_until_ready()\n")); 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 0
/* If we use sanei_usb_*, we sometimes lose interrupts! So poll the /* If we use sanei_usb_*, we sometimes lose interrupts! So poll the
* status here. */ * status here. */
error = query_status (s); RET_IF_ERR (query_status (s));
if (error < 0)
return error;
#endif #endif
} }
return 0; 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 static int
mp150_open (pixma_t * s) mp150_open (pixma_t * s)
{ {
@ -776,8 +990,13 @@ mp150_open (pixma_t * s)
if (s->cfg->pid == MP140_PID) if (s->cfg->pid == MP140_PID)
mp->generation = 2; mp->generation = 2;
/* TPU info data setup */
mp->tpu_datalen = 0;
query_status (s); query_status (s);
handle_interrupt (s, 200); handle_interrupt (s, 200);
if (mp->generation == 3 && has_ccd_sensor (s))
send_cmd_start_calibrate_ccd_3 (s);
return 0; return 0;
} }
@ -798,25 +1017,24 @@ mp150_check_param (pixma_t * s, pixma_scan_param_t * sp)
mp150_t *mp = (mp150_t *) s->subdriver; mp150_t *mp = (mp150_t *) s->subdriver;
sp->depth = 8; /* MP150 only supports 8 bit per channel. */ 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) if (mp->generation >= 2)
{ {
/* mod 32 and expansion of the X scan limits */ /* mod 32 and expansion of the X scan limits */
sp->w += (sp->x) % 32; sp->w += (sp->x) % 32;
sp->w = calc_raw_width (mp, sp); sp->w = calc_raw_width (mp, sp);
sp->x = ALIGN_INF (sp->x, 32); 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; return 0;
} }
static int static int
mp150_scan (pixma_t * s) mp150_scan (pixma_t * s)
{ {
int error = 0, tmo; int error = 0, tmo, i;
mp150_t *mp = (mp150_t *) s->subdriver; mp150_t *mp = (mp150_t *) s->subdriver;
if (mp->state != state_idle) if (mp->state != state_idle)
@ -835,11 +1053,7 @@ mp150_scan (pixma_t * s)
tmo = 10; tmo = 10;
while (!has_paper (s) && --tmo >= 0) while (!has_paper (s) && --tmo >= 0)
{ {
error = handle_interrupt (s, 1000); WAIT_INTERRUPT (1000);
if (s->cancel)
return PIXMA_ECANCELED;
if (error != PIXMA_ECANCELED && error < 0)
return error;
PDBG (pixma_dbg PDBG (pixma_dbg
(2, "No paper in ADF. Timed out in %d sec.\n", tmo)); (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; 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) error = send_cmd_e920 (s);
: send_cmd_start_calibrate_ccd_3 (s);
switch (error) switch (error)
{ {
case PIXMA_ECANCELED: case PIXMA_ECANCELED:
case PIXMA_EBUSY: case PIXMA_EBUSY:
PDBG (pixma_dbg PDBG (pixma_dbg (2, "cmd e920 or d520 returned %s\n",
(2, "cmd e920 or d520 returned %s\n", pixma_strerror (error))); pixma_strerror (error)));
/* fall through */ /* fall through */
case 0: case 0:
query_status (s); query_status (s);
break; break;
default: default:
PDBG (pixma_dbg PDBG (pixma_dbg (1, "WARNING:cmd e920 or d520 failed %s\n",
(1, "WARNING:cmd e920 or d520 failed %s\n", pixma_strerror (error))); pixma_strerror (error)));
return error; return error;
} }
tmo = 3; /* like Windows driver, CCD calibration ? */ tmo = 3; /* like Windows driver, CCD calibration ? */
while (--tmo >= 0) while (--tmo >= 0)
{ {
error = handle_interrupt (s, 1000); WAIT_INTERRUPT (1000);
if (s->cancel) PDBG (pixma_dbg (2, "CCD Calibration ends in %d sec.\n", tmo));
return PIXMA_ECANCELED;
if (error != PIXMA_ECANCELED && error < 0)
return error;
PDBG (pixma_dbg
(2, "CCD Calibration ends in %d sec.\n", tmo));
} }
/* pixma_sleep(2000000); */ /* pixma_sleep(2000000); */
} }
tmo = 10; tmo = 10;
if (s->param->adf_pageid == 0 || mp->generation <= 2)
{
error = start_session (s); error = start_session (s);
while (error == PIXMA_EBUSY && --tmo >= 0) while (error == PIXMA_EBUSY && --tmo >= 0)
{ {
@ -909,13 +1119,17 @@ mp150_scan (pixma_t * s)
if ((error >= 0) && (mp->generation <= 2)) if ((error >= 0) && (mp->generation <= 2))
error = select_source (s); error = select_source (s);
if ((error >= 0) && (mp->generation == 3) && has_ccd_sensor (s)) if ((error >= 0) && (mp->generation == 3) && has_ccd_sensor (s))
error = init_ccd_3 (s); error = init_ccd_lamp_3 (s);
if (error >= 0) if ((error >= 0) && !is_scanning_from_tpu (s))
error = send_gamma_table (s); for (i = (mp->generation == 3) ? 3 : 1 ; i > 0 && error >= 0; i--)
if ((error >= 0) && (mp->generation == 3))
error = send_gamma_table (s);
if ((error >= 0) && (mp->generation == 3))
error = send_gamma_table (s); 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) if (error >= 0)
error = send_scan_param (s); error = send_scan_param (s);
if ((error >= 0) && (mp->generation == 3)) if ((error >= 0) && (mp->generation == 3))
@ -928,98 +1142,6 @@ mp150_scan (pixma_t * s)
return 0; 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 static int
mp150_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) 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) if (mp->state == state_warmup)
{ {
error = wait_until_ready (s); RET_IF_ERR (wait_until_ready (s));
if (error < 0)
return error;
pixma_sleep (1000000); /* No need to sleep, actually, but Window's driver pixma_sleep (1000000); /* No need to sleep, actually, but Window's driver
* sleep 1.5 sec. */ * sleep 1.5 sec. */
mp->state = state_scanning; mp->state = state_scanning;
@ -1054,8 +1174,7 @@ mp150_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib)
if (s->cancel) if (s->cancel)
return PIXMA_ECANCELED; return PIXMA_ECANCELED;
if ((mp->last_block & 0x28) == 0x28) if ((mp->last_block & 0x28) == 0x28)
{ { /* end of image */
/* end of image */
mp->state = state_finished; mp->state = state_finished;
return 0; return 0;
} }
@ -1082,11 +1201,15 @@ mp150_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib)
PASSERT (bytes_received == block_size); PASSERT (bytes_received == block_size);
if (block_size == 0) if (block_size == 0)
{ { /* no image data at this moment. */
/* no image data at this moment. */
pixma_sleep (10000); 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_ofs = mp->imgbuf + mp->data_left_len + bytes_received;
mp->data_left_len = post_process_image_data (s, ib); mp->data_left_len = post_process_image_data (s, ib);
mp->data_left_ofs -= mp->data_left_len; mp->data_left_ofs -= mp->data_left_len;
@ -1109,17 +1232,20 @@ mp150_finish_scan (pixma_t * s)
/* fall through */ /* fall through */
case state_scanning: case state_scanning:
case state_warmup: 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: 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 /* FIXME: to process several pages ADF scan, must not send
* abort_session and start_session between pages (last_block=0x28) * abort_session and start_session between pages (last_block=0x28)
* if (mp->last_block != 0x28 || !is_scanning_from_adf(s)) */ * if (mp->last_block != 0x28 || !is_scanning_from_adf(s)) */
if (mp->last_block != 0x38) if (mp->generation <= 2 || !is_scanning_from_adf (s) || mp->last_block == 0x38)
abort_session (s); /* FIXME: it probably doesn't work in duplex mode! */ {
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; mp->state = state_idle;
}
/* fall through */ /* fall through */
case state_idle: case state_idle:
break; break;
@ -1141,9 +1267,7 @@ mp150_get_status (pixma_t * s, pixma_device_status_t * status)
{ {
int error; int error;
error = query_status (s); RET_IF_ERR (query_status (s));
if (error < 0)
return error;
status->hardware = PIXMA_HARDWARE_OK; status->hardware = PIXMA_HARDWARE_OK;
status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER;
status->cal = status->cal =

Wyświetl plik

@ -158,7 +158,7 @@
:interface "USB" :interface "USB"
:usbid "0x04a9" "0x1713" :usbid "0x04a9" "0x1713"
:status :basic :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" :model "PIXMA MP960"
:interface "USB" :interface "USB"
@ -169,7 +169,7 @@
:interface "USB" :interface "USB"
:usbid "0x04a9" "0x1726" :usbid "0x04a9" "0x1726"
:status :good :status :good
:comment "All resolutions supported (up to 4800DPI)" :comment "All resolutions supported (up to 4800DPI). TPU support currently experimental."
:model "SmartBase MP360" :model "SmartBase MP360"
:interface "USB" :interface "USB"
@ -240,8 +240,8 @@
:model "PIXMA MX7600" :model "PIXMA MX7600"
:interface "USB" :interface "USB"
:usbid "0x04a9" "0x171c" :usbid "0x04a9" "0x171c"
:status :untested :status :good
:comment "Generation 3 protocol? Testers needed!" :comment "Flatbed and ADF scan. All resolutions supported (up to 4800DPI)"
:model "imageCLASS MF5630" :model "imageCLASS MF5630"
:interface "USB" :interface "USB"

Wyświetl plik

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