1141cc406Sopenharmony_ci/* SANE - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de> 4141cc406Sopenharmony_ci Copyright (C) 2007-2009 Nicolas Martin, <nicols-guest at alioth dot debian dot org> 5141cc406Sopenharmony_ci Copyright (C) 2008 Dennis Lou, dlou 99 at yahoo dot com 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This file is part of the SANE package. 8141cc406Sopenharmony_ci 9141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 10141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 11141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 12141cc406Sopenharmony_ci License, or (at your option) any later version. 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 15141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 16141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17141cc406Sopenharmony_ci General Public License for more details. 18141cc406Sopenharmony_ci 19141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 20141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 21141cc406Sopenharmony_ci 22141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 23141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 24141cc406Sopenharmony_ci 25141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 26141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 27141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 28141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 29141cc406Sopenharmony_ci account of linking the SANE library code into it. 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 32141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 33141cc406Sopenharmony_ci License. 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 36141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 37141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 40141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 41141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 42141cc406Sopenharmony_ci */ 43141cc406Sopenharmony_ci 44141cc406Sopenharmony_ci/* 45141cc406Sopenharmony_ci * imageCLASS backend based on pixma_mp730.c 46141cc406Sopenharmony_ci */ 47141cc406Sopenharmony_ci 48141cc406Sopenharmony_ci#include "../include/sane/config.h" 49141cc406Sopenharmony_ci 50141cc406Sopenharmony_ci#include <stdio.h> 51141cc406Sopenharmony_ci#include <stdlib.h> 52141cc406Sopenharmony_ci#include <string.h> 53141cc406Sopenharmony_ci 54141cc406Sopenharmony_ci#include "pixma_rename.h" 55141cc406Sopenharmony_ci#include "pixma_common.h" 56141cc406Sopenharmony_ci#include "pixma_io.h" 57141cc406Sopenharmony_ci 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci#ifdef __GNUC__ 60141cc406Sopenharmony_ci# define UNUSED(v) (void) v 61141cc406Sopenharmony_ci#else 62141cc406Sopenharmony_ci# define UNUSED(v) 63141cc406Sopenharmony_ci#endif 64141cc406Sopenharmony_ci 65141cc406Sopenharmony_ci#define IMAGE_BLOCK_SIZE (0x80000) 66141cc406Sopenharmony_ci#define MAX_CHUNK_SIZE (0x1000) 67141cc406Sopenharmony_ci#define MIN_CHUNK_SIZE (0x0200) 68141cc406Sopenharmony_ci#define CMDBUF_SIZE 512 69141cc406Sopenharmony_ci 70141cc406Sopenharmony_ci#define MF4100_PID 0x26a3 71141cc406Sopenharmony_ci#define MF4600_PID 0x26b0 72141cc406Sopenharmony_ci#define MF4010_PID 0x26b4 73141cc406Sopenharmony_ci#define MF4200_PID 0x26b5 74141cc406Sopenharmony_ci#define MF4360_PID 0x26ec 75141cc406Sopenharmony_ci#define D480_PID 0x26ed 76141cc406Sopenharmony_ci#define MF4320_PID 0x26ee 77141cc406Sopenharmony_ci#define D420_PID 0x26ef 78141cc406Sopenharmony_ci#define MF3200_PID 0x2684 79141cc406Sopenharmony_ci#define MF6500_PID 0x2686 80141cc406Sopenharmony_ci#define IR1018_PID 0x269d 81141cc406Sopenharmony_ci/* generation 2 scanners (>=0x2707) */ 82141cc406Sopenharmony_ci#define MF8300_PID 0x2708 83141cc406Sopenharmony_ci#define MF4500_PID 0x2736 84141cc406Sopenharmony_ci#define MF4410_PID 0x2737 85141cc406Sopenharmony_ci#define D550_PID 0x2738 86141cc406Sopenharmony_ci#define MF3010_PID 0x2759 87141cc406Sopenharmony_ci#define MF4570_PID 0x275a 88141cc406Sopenharmony_ci#define MF4800_PID 0x2773 89141cc406Sopenharmony_ci#define MF4700_PID 0x2774 90141cc406Sopenharmony_ci#define MF8200_PID 0x2779 91141cc406Sopenharmony_ci/* the following are all untested */ 92141cc406Sopenharmony_ci#define MF8100_PID 0x2659 93141cc406Sopenharmony_ci#define MF5880_PID 0x26f9 94141cc406Sopenharmony_ci#define MF6680_PID 0x26fa 95141cc406Sopenharmony_ci#define MF8030_PID 0x2707 96141cc406Sopenharmony_ci#define IR1133_PID 0x2742 97141cc406Sopenharmony_ci#define MF5900_PID 0x2743 98141cc406Sopenharmony_ci#define D530_PID 0x2775 99141cc406Sopenharmony_ci#define MF8500_PID 0x277a 100141cc406Sopenharmony_ci#define MF6100_PID 0x278e 101141cc406Sopenharmony_ci#define MF820_PID 0x27a6 102141cc406Sopenharmony_ci#define MF220_PID 0x27a8 103141cc406Sopenharmony_ci#define MF210_PID 0x27a9 104141cc406Sopenharmony_ci#define MF620_PID 0x27b4 105141cc406Sopenharmony_ci#define MF720_PID 0x27b5 106141cc406Sopenharmony_ci#define MF410_PID 0x27c0 107141cc406Sopenharmony_ci#define MF510_PID 0x27c2 108141cc406Sopenharmony_ci#define MF230_PID 0x27d1 109141cc406Sopenharmony_ci#define MF240_PID 0x27d2 110141cc406Sopenharmony_ci#define MF630_PID 0x27e1 111141cc406Sopenharmony_ci#define MF634_PID 0x27e2 112141cc406Sopenharmony_ci#define MF730_PID 0x27e4 113141cc406Sopenharmony_ci#define MF731_PID 0x27e5 114141cc406Sopenharmony_ci#define D570_PID 0x27e8 115141cc406Sopenharmony_ci#define MF110_PID 0x27ed 116141cc406Sopenharmony_ci#define MF520_PID 0x27f0 117141cc406Sopenharmony_ci#define MF420_PID 0x27f1 118141cc406Sopenharmony_ci#define MF260_PID 0x27f4 119141cc406Sopenharmony_ci#define MF740_PID 0x27fb 120141cc406Sopenharmony_ci#define MF743_PID 0x27fc 121141cc406Sopenharmony_ci#define MF640_PID 0x27fe 122141cc406Sopenharmony_ci#define MF645_PID 0x27fd 123141cc406Sopenharmony_ci#define MF440_PID 0x2823 124141cc406Sopenharmony_ci 125141cc406Sopenharmony_ci 126141cc406Sopenharmony_cienum iclass_state_t 127141cc406Sopenharmony_ci{ 128141cc406Sopenharmony_ci state_idle, 129141cc406Sopenharmony_ci state_warmup, /* MF4200 always warm/calibrated; others? */ 130141cc406Sopenharmony_ci state_scanning, 131141cc406Sopenharmony_ci state_finished 132141cc406Sopenharmony_ci}; 133141cc406Sopenharmony_ci 134141cc406Sopenharmony_cienum iclass_cmd_t 135141cc406Sopenharmony_ci{ 136141cc406Sopenharmony_ci cmd_start_session = 0xdb20, 137141cc406Sopenharmony_ci cmd_select_source = 0xdd20, 138141cc406Sopenharmony_ci cmd_scan_param = 0xde20, 139141cc406Sopenharmony_ci cmd_status = 0xf320, 140141cc406Sopenharmony_ci cmd_abort_session = 0xef20, 141141cc406Sopenharmony_ci cmd_read_image = 0xd420, 142141cc406Sopenharmony_ci cmd_read_image2 = 0xd460, /* New multifunctionals, such as MF4410 */ 143141cc406Sopenharmony_ci cmd_error_info = 0xff20, 144141cc406Sopenharmony_ci 145141cc406Sopenharmony_ci cmd_activate = 0xcf60 146141cc406Sopenharmony_ci}; 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_citypedef struct iclass_t 149141cc406Sopenharmony_ci{ 150141cc406Sopenharmony_ci enum iclass_state_t state; 151141cc406Sopenharmony_ci pixma_cmdbuf_t cb; 152141cc406Sopenharmony_ci unsigned raw_width; 153141cc406Sopenharmony_ci uint8_t current_status[12]; 154141cc406Sopenharmony_ci 155141cc406Sopenharmony_ci uint8_t *buf, *blkptr, *lineptr; 156141cc406Sopenharmony_ci unsigned buf_len, blk_len; 157141cc406Sopenharmony_ci 158141cc406Sopenharmony_ci unsigned last_block; 159141cc406Sopenharmony_ci 160141cc406Sopenharmony_ci uint8_t generation; /* New multifunctionals are (generation == 2) */ 161141cc406Sopenharmony_ci 162141cc406Sopenharmony_ci uint8_t adf_state; /* handle adf scanning */ 163141cc406Sopenharmony_ci} iclass_t; 164141cc406Sopenharmony_ci 165141cc406Sopenharmony_ci 166141cc406Sopenharmony_cistatic int is_scanning_from_adf (pixma_t * s) 167141cc406Sopenharmony_ci{ 168141cc406Sopenharmony_ci return (s->param->source == PIXMA_SOURCE_ADF 169141cc406Sopenharmony_ci || s->param->source == PIXMA_SOURCE_ADFDUP); 170141cc406Sopenharmony_ci} 171141cc406Sopenharmony_ci 172141cc406Sopenharmony_cistatic int is_scanning_from_adfdup (pixma_t * s) 173141cc406Sopenharmony_ci{ 174141cc406Sopenharmony_ci return (s->param->source == PIXMA_SOURCE_ADFDUP); 175141cc406Sopenharmony_ci} 176141cc406Sopenharmony_ci 177141cc406Sopenharmony_cistatic void iclass_finish_scan (pixma_t * s); 178141cc406Sopenharmony_ci 179141cc406Sopenharmony_ci/* checksumming is sometimes different than pixmas */ 180141cc406Sopenharmony_cistatic int 181141cc406Sopenharmony_ciiclass_exec (pixma_t * s, pixma_cmdbuf_t * cb, char invcksum) 182141cc406Sopenharmony_ci{ 183141cc406Sopenharmony_ci if (cb->cmdlen > cb->cmd_header_len) 184141cc406Sopenharmony_ci pixma_fill_checksum (cb->buf + cb->cmd_header_len, 185141cc406Sopenharmony_ci cb->buf + cb->cmdlen - 2); 186141cc406Sopenharmony_ci cb->buf[cb->cmdlen - 1] = invcksum ? -cb->buf[cb->cmdlen - 2] : 0; 187141cc406Sopenharmony_ci cb->reslen = 188141cc406Sopenharmony_ci pixma_cmd_transaction (s, cb->buf, cb->cmdlen, cb->buf, 189141cc406Sopenharmony_ci cb->expected_reslen); 190141cc406Sopenharmony_ci return pixma_check_result (cb); 191141cc406Sopenharmony_ci} 192141cc406Sopenharmony_ci 193141cc406Sopenharmony_cistatic int 194141cc406Sopenharmony_cihas_paper (pixma_t * s) 195141cc406Sopenharmony_ci{ 196141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 197141cc406Sopenharmony_ci return ((mf->current_status[1] & 0x0f) == 0 /* allow 0x10 as ADF paper OK */ 198141cc406Sopenharmony_ci || mf->current_status[1] == 81); /* allow 0x51 as ADF paper OK */ 199141cc406Sopenharmony_ci} 200141cc406Sopenharmony_ci 201141cc406Sopenharmony_cistatic int 202141cc406Sopenharmony_ciabort_session (pixma_t * s) 203141cc406Sopenharmony_ci{ 204141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 205141cc406Sopenharmony_ci return pixma_exec_short_cmd (s, &mf->cb, cmd_abort_session); 206141cc406Sopenharmony_ci} 207141cc406Sopenharmony_ci 208141cc406Sopenharmony_cistatic int 209141cc406Sopenharmony_ciquery_status (pixma_t * s) 210141cc406Sopenharmony_ci{ 211141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 212141cc406Sopenharmony_ci uint8_t *data; 213141cc406Sopenharmony_ci int error; 214141cc406Sopenharmony_ci 215141cc406Sopenharmony_ci data = pixma_newcmd (&mf->cb, cmd_status, 0, 12); 216141cc406Sopenharmony_ci error = pixma_exec (s, &mf->cb); 217141cc406Sopenharmony_ci if (error >= 0) 218141cc406Sopenharmony_ci { 219141cc406Sopenharmony_ci memcpy (mf->current_status, data, 12); 220141cc406Sopenharmony_ci /*DBG (3, "Current status: paper=0x%02x cal=%u lamp=%u\n", 221141cc406Sopenharmony_ci data[1], data[8], data[7]);*/ 222141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "Current status: paper=0x%02x cal=%u lamp=%u\n", 223141cc406Sopenharmony_ci data[1], data[8], data[7])); 224141cc406Sopenharmony_ci } 225141cc406Sopenharmony_ci return error; 226141cc406Sopenharmony_ci} 227141cc406Sopenharmony_ci 228141cc406Sopenharmony_cistatic int 229141cc406Sopenharmony_ciactivate (pixma_t * s, uint8_t x) 230141cc406Sopenharmony_ci{ 231141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 232141cc406Sopenharmony_ci uint8_t *data = pixma_newcmd (&mf->cb, cmd_activate, 10, 0); 233141cc406Sopenharmony_ci data[0] = 1; 234141cc406Sopenharmony_ci data[3] = x; 235141cc406Sopenharmony_ci switch (s->cfg->pid) 236141cc406Sopenharmony_ci { 237141cc406Sopenharmony_ci case MF4200_PID: 238141cc406Sopenharmony_ci case MF4600_PID: 239141cc406Sopenharmony_ci case MF6500_PID: 240141cc406Sopenharmony_ci case D480_PID: 241141cc406Sopenharmony_ci case D420_PID: 242141cc406Sopenharmony_ci case MF4360_PID: 243141cc406Sopenharmony_ci case MF4100_PID: 244141cc406Sopenharmony_ci case MF8300_PID: 245141cc406Sopenharmony_ci case IR1018_PID: 246141cc406Sopenharmony_ci return iclass_exec (s, &mf->cb, 1); 247141cc406Sopenharmony_ci break; 248141cc406Sopenharmony_ci default: 249141cc406Sopenharmony_ci return pixma_exec (s, &mf->cb); 250141cc406Sopenharmony_ci } 251141cc406Sopenharmony_ci} 252141cc406Sopenharmony_ci 253141cc406Sopenharmony_cistatic int 254141cc406Sopenharmony_cistart_session (pixma_t * s) 255141cc406Sopenharmony_ci{ 256141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 257141cc406Sopenharmony_ci return pixma_exec_short_cmd (s, &mf->cb, cmd_start_session); 258141cc406Sopenharmony_ci} 259141cc406Sopenharmony_ci 260141cc406Sopenharmony_cistatic int 261141cc406Sopenharmony_ciselect_source (pixma_t * s) 262141cc406Sopenharmony_ci{ 263141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 264141cc406Sopenharmony_ci uint8_t *data = pixma_newcmd (&mf->cb, cmd_select_source, 10, 0); 265141cc406Sopenharmony_ci data[0] = (is_scanning_from_adf(s)) ? 2 : 1; 266141cc406Sopenharmony_ci /* special settings for MF6100 */ 267141cc406Sopenharmony_ci data[5] = is_scanning_from_adfdup(s) ? 3 : ((s->cfg->pid == MF6100_PID && s->param->source == PIXMA_SOURCE_ADF) ? 1 : 0); 268141cc406Sopenharmony_ci switch (s->cfg->pid) 269141cc406Sopenharmony_ci { 270141cc406Sopenharmony_ci case MF4200_PID: 271141cc406Sopenharmony_ci case MF4600_PID: 272141cc406Sopenharmony_ci case MF6500_PID: 273141cc406Sopenharmony_ci case D480_PID: 274141cc406Sopenharmony_ci case D420_PID: 275141cc406Sopenharmony_ci case MF4360_PID: 276141cc406Sopenharmony_ci case MF4100_PID: 277141cc406Sopenharmony_ci case MF8300_PID: 278141cc406Sopenharmony_ci case IR1018_PID: 279141cc406Sopenharmony_ci return iclass_exec (s, &mf->cb, 0); 280141cc406Sopenharmony_ci break; 281141cc406Sopenharmony_ci default: 282141cc406Sopenharmony_ci return pixma_exec (s, &mf->cb); 283141cc406Sopenharmony_ci } 284141cc406Sopenharmony_ci} 285141cc406Sopenharmony_ci 286141cc406Sopenharmony_cistatic int 287141cc406Sopenharmony_cisend_scan_param (pixma_t * s) 288141cc406Sopenharmony_ci{ 289141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 290141cc406Sopenharmony_ci uint8_t *data; 291141cc406Sopenharmony_ci 292141cc406Sopenharmony_ci data = pixma_newcmd (&mf->cb, cmd_scan_param, 0x2e, 0); 293141cc406Sopenharmony_ci pixma_set_be16 (s->param->xdpi | 0x1000, data + 0x04); 294141cc406Sopenharmony_ci pixma_set_be16 (s->param->ydpi | 0x1000, data + 0x06); 295141cc406Sopenharmony_ci pixma_set_be32 (s->param->x, data + 0x08); 296141cc406Sopenharmony_ci pixma_set_be32 (s->param->y, data + 0x0c); 297141cc406Sopenharmony_ci pixma_set_be32 (mf->raw_width, data + 0x10); 298141cc406Sopenharmony_ci pixma_set_be32 (s->param->h, data + 0x14); 299141cc406Sopenharmony_ci data[0x18] = (s->param->channels == 1) ? 0x04 : 0x08; 300141cc406Sopenharmony_ci data[0x19] = s->param->channels * ((s->param->depth == 1) ? 8 : s->param->depth); /* bits per pixel */ 301141cc406Sopenharmony_ci data[0x1f] = 0x7f; 302141cc406Sopenharmony_ci data[0x20] = 0xff; 303141cc406Sopenharmony_ci data[0x23] = 0x81; 304141cc406Sopenharmony_ci switch (s->cfg->pid) 305141cc406Sopenharmony_ci { 306141cc406Sopenharmony_ci case MF4200_PID: 307141cc406Sopenharmony_ci case MF4600_PID: 308141cc406Sopenharmony_ci case MF6500_PID: 309141cc406Sopenharmony_ci case D480_PID: 310141cc406Sopenharmony_ci case D420_PID: 311141cc406Sopenharmony_ci case MF4360_PID: 312141cc406Sopenharmony_ci case MF4100_PID: 313141cc406Sopenharmony_ci case MF8300_PID: 314141cc406Sopenharmony_ci case IR1018_PID: 315141cc406Sopenharmony_ci return iclass_exec (s, &mf->cb, 0); 316141cc406Sopenharmony_ci break; 317141cc406Sopenharmony_ci default: 318141cc406Sopenharmony_ci return pixma_exec (s, &mf->cb); 319141cc406Sopenharmony_ci } 320141cc406Sopenharmony_ci} 321141cc406Sopenharmony_ci 322141cc406Sopenharmony_cistatic int 323141cc406Sopenharmony_cirequest_image_block (pixma_t * s, unsigned flag, uint8_t * info, 324141cc406Sopenharmony_ci unsigned * size, uint8_t * data, unsigned * datalen) 325141cc406Sopenharmony_ci{ 326141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 327141cc406Sopenharmony_ci int error; 328141cc406Sopenharmony_ci unsigned expected_len; 329141cc406Sopenharmony_ci const int hlen = 2 + 6; 330141cc406Sopenharmony_ci 331141cc406Sopenharmony_ci memset (mf->cb.buf, 0, 11); 332141cc406Sopenharmony_ci /* generation 2 scanners use cmd_read_image2. 333141cc406Sopenharmony_ci * MF6100, ... are exceptions */ 334141cc406Sopenharmony_ci pixma_set_be16 (((mf->generation >= 2 335141cc406Sopenharmony_ci && s->cfg->pid != MF6100_PID) ? cmd_read_image2 : cmd_read_image), mf->cb.buf); 336141cc406Sopenharmony_ci mf->cb.buf[8] = flag; 337141cc406Sopenharmony_ci mf->cb.buf[10] = 0x06; 338141cc406Sopenharmony_ci expected_len = (mf->generation >= 2 || 339141cc406Sopenharmony_ci s->cfg->pid == MF4600_PID || 340141cc406Sopenharmony_ci s->cfg->pid == MF6500_PID || 341141cc406Sopenharmony_ci s->cfg->pid == MF8030_PID || 342141cc406Sopenharmony_ci s->cfg->pid == IR1018_PID) ? 512 : hlen; 343141cc406Sopenharmony_ci mf->cb.reslen = pixma_cmd_transaction (s, mf->cb.buf, 11, mf->cb.buf, expected_len); 344141cc406Sopenharmony_ci if (mf->cb.reslen >= hlen) 345141cc406Sopenharmony_ci { 346141cc406Sopenharmony_ci *info = mf->cb.buf[2]; 347141cc406Sopenharmony_ci *size = pixma_get_be16 (mf->cb.buf + 6); /* 16bit size */ 348141cc406Sopenharmony_ci error = 0; 349141cc406Sopenharmony_ci 350141cc406Sopenharmony_ci if (mf->generation >= 2 || 351141cc406Sopenharmony_ci s->cfg->pid == MF4600_PID || 352141cc406Sopenharmony_ci s->cfg->pid == MF6500_PID || 353141cc406Sopenharmony_ci s->cfg->pid == MF8030_PID || 354141cc406Sopenharmony_ci s->cfg->pid == IR1018_PID) 355141cc406Sopenharmony_ci { /* 32bit size */ 356141cc406Sopenharmony_ci *datalen = mf->cb.reslen - hlen; 357141cc406Sopenharmony_ci *size = (*datalen + hlen == 512) ? pixma_get_be32 (mf->cb.buf + 4) - *datalen : *size; 358141cc406Sopenharmony_ci memcpy (data, mf->cb.buf + hlen, *datalen); 359141cc406Sopenharmony_ci } 360141cc406Sopenharmony_ci PDBG (pixma_dbg (11, "*request_image_block***** size = %u *****\n", *size)); 361141cc406Sopenharmony_ci } 362141cc406Sopenharmony_ci else 363141cc406Sopenharmony_ci { 364141cc406Sopenharmony_ci error = PIXMA_EPROTO; 365141cc406Sopenharmony_ci } 366141cc406Sopenharmony_ci return error; 367141cc406Sopenharmony_ci} 368141cc406Sopenharmony_ci 369141cc406Sopenharmony_cistatic int 370141cc406Sopenharmony_ciread_image_block (pixma_t * s, uint8_t * data, unsigned size) 371141cc406Sopenharmony_ci{ 372141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 373141cc406Sopenharmony_ci int error; 374141cc406Sopenharmony_ci unsigned maxchunksize, chunksize, count = 0; 375141cc406Sopenharmony_ci 376141cc406Sopenharmony_ci maxchunksize = MAX_CHUNK_SIZE * ((mf->generation >= 2 || 377141cc406Sopenharmony_ci s->cfg->pid == MF4600_PID || 378141cc406Sopenharmony_ci s->cfg->pid == MF6500_PID || 379141cc406Sopenharmony_ci s->cfg->pid == MF8030_PID || 380141cc406Sopenharmony_ci s->cfg->pid == IR1018_PID) ? 4 : 1); 381141cc406Sopenharmony_ci while (size) 382141cc406Sopenharmony_ci { 383141cc406Sopenharmony_ci if (size >= maxchunksize) 384141cc406Sopenharmony_ci chunksize = maxchunksize; 385141cc406Sopenharmony_ci else if (size < MIN_CHUNK_SIZE) 386141cc406Sopenharmony_ci chunksize = size; 387141cc406Sopenharmony_ci else 388141cc406Sopenharmony_ci chunksize = size - (size % MIN_CHUNK_SIZE); 389141cc406Sopenharmony_ci error = pixma_read (s->io, data, chunksize); 390141cc406Sopenharmony_ci if (error < 0) 391141cc406Sopenharmony_ci return count; 392141cc406Sopenharmony_ci count += error; 393141cc406Sopenharmony_ci data += error; 394141cc406Sopenharmony_ci size -= error; 395141cc406Sopenharmony_ci } 396141cc406Sopenharmony_ci return count; 397141cc406Sopenharmony_ci} 398141cc406Sopenharmony_ci 399141cc406Sopenharmony_cistatic int 400141cc406Sopenharmony_ciread_error_info (pixma_t * s, void *buf, unsigned size) 401141cc406Sopenharmony_ci{ 402141cc406Sopenharmony_ci unsigned len = 16; 403141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 404141cc406Sopenharmony_ci uint8_t *data; 405141cc406Sopenharmony_ci int error; 406141cc406Sopenharmony_ci 407141cc406Sopenharmony_ci data = pixma_newcmd (&mf->cb, cmd_error_info, 0, len); 408141cc406Sopenharmony_ci switch (s->cfg->pid) 409141cc406Sopenharmony_ci { 410141cc406Sopenharmony_ci case MF4200_PID: 411141cc406Sopenharmony_ci case MF4600_PID: 412141cc406Sopenharmony_ci case MF6500_PID: 413141cc406Sopenharmony_ci case D480_PID: 414141cc406Sopenharmony_ci case D420_PID: 415141cc406Sopenharmony_ci case MF4360_PID: 416141cc406Sopenharmony_ci case MF4100_PID: 417141cc406Sopenharmony_ci case MF8300_PID: 418141cc406Sopenharmony_ci case IR1018_PID: 419141cc406Sopenharmony_ci error = iclass_exec (s, &mf->cb, 0); 420141cc406Sopenharmony_ci break; 421141cc406Sopenharmony_ci default: 422141cc406Sopenharmony_ci error = pixma_exec (s, &mf->cb); 423141cc406Sopenharmony_ci } 424141cc406Sopenharmony_ci if (error < 0) 425141cc406Sopenharmony_ci return error; 426141cc406Sopenharmony_ci if (buf && len < size) 427141cc406Sopenharmony_ci { 428141cc406Sopenharmony_ci size = len; 429141cc406Sopenharmony_ci /* NOTE: I've absolutely no idea what the returned data mean. */ 430141cc406Sopenharmony_ci memcpy (buf, data, size); 431141cc406Sopenharmony_ci error = len; 432141cc406Sopenharmony_ci } 433141cc406Sopenharmony_ci return error; 434141cc406Sopenharmony_ci} 435141cc406Sopenharmony_ci 436141cc406Sopenharmony_cistatic int 437141cc406Sopenharmony_cihandle_interrupt (pixma_t * s, int timeout) 438141cc406Sopenharmony_ci{ 439141cc406Sopenharmony_ci uint8_t buf[16]; 440141cc406Sopenharmony_ci int len; 441141cc406Sopenharmony_ci 442141cc406Sopenharmony_ci len = pixma_wait_interrupt (s->io, buf, sizeof (buf), timeout); 443141cc406Sopenharmony_ci if (len == PIXMA_ETIMEDOUT) 444141cc406Sopenharmony_ci return 0; 445141cc406Sopenharmony_ci if (len < 0) 446141cc406Sopenharmony_ci return len; 447141cc406Sopenharmony_ci if (len != 16) 448141cc406Sopenharmony_ci { 449141cc406Sopenharmony_ci PDBG (pixma_dbg 450141cc406Sopenharmony_ci (1, "WARNING:unexpected interrupt packet length %d\n", len)); 451141cc406Sopenharmony_ci return PIXMA_EPROTO; 452141cc406Sopenharmony_ci } 453141cc406Sopenharmony_ci if (buf[12] & 0x40) 454141cc406Sopenharmony_ci query_status (s); 455141cc406Sopenharmony_ci if (buf[15] & 1) 456141cc406Sopenharmony_ci s->events = PIXMA_EV_BUTTON1; 457141cc406Sopenharmony_ci return 1; 458141cc406Sopenharmony_ci} 459141cc406Sopenharmony_ci 460141cc406Sopenharmony_cistatic int 461141cc406Sopenharmony_cistep1 (pixma_t * s) 462141cc406Sopenharmony_ci{ 463141cc406Sopenharmony_ci int error; 464141cc406Sopenharmony_ci int rec_tmo; 465141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 466141cc406Sopenharmony_ci 467141cc406Sopenharmony_ci /* don't wait full timeout for 1st command */ 468141cc406Sopenharmony_ci rec_tmo = s->rec_tmo; /* save global timeout */ 469141cc406Sopenharmony_ci s->rec_tmo = 2; /* set timeout to 2 seconds */ 470141cc406Sopenharmony_ci error = query_status (s); 471141cc406Sopenharmony_ci s->rec_tmo = rec_tmo; /* restore global timeout */ 472141cc406Sopenharmony_ci if (error < 0) 473141cc406Sopenharmony_ci { 474141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING: Resend first USB command after timeout!\n")); 475141cc406Sopenharmony_ci error = query_status (s); 476141cc406Sopenharmony_ci } 477141cc406Sopenharmony_ci if (error < 0) 478141cc406Sopenharmony_ci return error; 479141cc406Sopenharmony_ci 480141cc406Sopenharmony_ci /* wait for inserted paper */ 481141cc406Sopenharmony_ci if (s->param->adf_wait != 0 && is_scanning_from_adf(s)) 482141cc406Sopenharmony_ci { 483141cc406Sopenharmony_ci int tmo = s->param->adf_wait; 484141cc406Sopenharmony_ci 485141cc406Sopenharmony_ci while (!has_paper (s) && --tmo >= 0 && !s->param->frontend_cancel) 486141cc406Sopenharmony_ci { 487141cc406Sopenharmony_ci if ((error = query_status (s)) < 0) 488141cc406Sopenharmony_ci return error; 489141cc406Sopenharmony_ci pixma_sleep (1000000); 490141cc406Sopenharmony_ci PDBG (pixma_dbg(2, "No paper in ADF. Timed out in %d sec.\n", tmo)); 491141cc406Sopenharmony_ci } 492141cc406Sopenharmony_ci /* canceled from frontend */ 493141cc406Sopenharmony_ci if (s->param->frontend_cancel) 494141cc406Sopenharmony_ci { 495141cc406Sopenharmony_ci return PIXMA_ECANCELED; 496141cc406Sopenharmony_ci } 497141cc406Sopenharmony_ci } 498141cc406Sopenharmony_ci /* no paper inserted 499141cc406Sopenharmony_ci * => abort session */ 500141cc406Sopenharmony_ci if (is_scanning_from_adf(s) && !has_paper (s)) 501141cc406Sopenharmony_ci { 502141cc406Sopenharmony_ci return PIXMA_ENO_PAPER; 503141cc406Sopenharmony_ci } 504141cc406Sopenharmony_ci /* activate only seen for generation 1 scanners */ 505141cc406Sopenharmony_ci if (mf->generation == 1) 506141cc406Sopenharmony_ci { 507141cc406Sopenharmony_ci if (error >= 0) 508141cc406Sopenharmony_ci error = activate (s, 0); 509141cc406Sopenharmony_ci if (error >= 0) 510141cc406Sopenharmony_ci error = activate (s, 4); 511141cc406Sopenharmony_ci } 512141cc406Sopenharmony_ci return error; 513141cc406Sopenharmony_ci} 514141cc406Sopenharmony_ci 515141cc406Sopenharmony_ci/* line in=rrr... ggg... bbb... line out=rgbrgbrgb... */ 516141cc406Sopenharmony_cistatic void 517141cc406Sopenharmony_cipack_rgb (const uint8_t * src, unsigned nlines, unsigned w, uint8_t * dst) 518141cc406Sopenharmony_ci{ 519141cc406Sopenharmony_ci unsigned w2, stride; 520141cc406Sopenharmony_ci 521141cc406Sopenharmony_ci w2 = 2 * w; 522141cc406Sopenharmony_ci stride = 3 * w; 523141cc406Sopenharmony_ci for (; nlines != 0; nlines--) 524141cc406Sopenharmony_ci { 525141cc406Sopenharmony_ci unsigned x; 526141cc406Sopenharmony_ci for (x = 0; x != w; x++) 527141cc406Sopenharmony_ci { 528141cc406Sopenharmony_ci *dst++ = src[x + 0]; 529141cc406Sopenharmony_ci *dst++ = src[x + w]; 530141cc406Sopenharmony_ci *dst++ = src[x + w2]; 531141cc406Sopenharmony_ci } 532141cc406Sopenharmony_ci src += stride; 533141cc406Sopenharmony_ci } 534141cc406Sopenharmony_ci} 535141cc406Sopenharmony_ci 536141cc406Sopenharmony_cistatic int 537141cc406Sopenharmony_ciiclass_open (pixma_t * s) 538141cc406Sopenharmony_ci{ 539141cc406Sopenharmony_ci iclass_t *mf; 540141cc406Sopenharmony_ci uint8_t *buf; 541141cc406Sopenharmony_ci 542141cc406Sopenharmony_ci mf = (iclass_t *) calloc (1, sizeof (*mf)); 543141cc406Sopenharmony_ci if (!mf) 544141cc406Sopenharmony_ci return PIXMA_ENOMEM; 545141cc406Sopenharmony_ci 546141cc406Sopenharmony_ci buf = (uint8_t *) malloc (CMDBUF_SIZE); 547141cc406Sopenharmony_ci if (!buf) 548141cc406Sopenharmony_ci { 549141cc406Sopenharmony_ci free (mf); 550141cc406Sopenharmony_ci return PIXMA_ENOMEM; 551141cc406Sopenharmony_ci } 552141cc406Sopenharmony_ci 553141cc406Sopenharmony_ci s->subdriver = mf; 554141cc406Sopenharmony_ci mf->state = state_idle; 555141cc406Sopenharmony_ci 556141cc406Sopenharmony_ci mf->cb.buf = buf; 557141cc406Sopenharmony_ci mf->cb.size = CMDBUF_SIZE; 558141cc406Sopenharmony_ci mf->cb.res_header_len = 2; 559141cc406Sopenharmony_ci mf->cb.cmd_header_len = 10; 560141cc406Sopenharmony_ci mf->cb.cmd_len_field_ofs = 7; 561141cc406Sopenharmony_ci 562141cc406Sopenharmony_ci /* adf scanning */ 563141cc406Sopenharmony_ci mf->adf_state = state_idle; 564141cc406Sopenharmony_ci 565141cc406Sopenharmony_ci /* set generation = 2 for new multifunctionals */ 566141cc406Sopenharmony_ci mf->generation = (s->cfg->pid >= MF8030_PID) ? 2 : 1; 567141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "*iclass_open***** This is a generation %d scanner. *****\n", mf->generation)); 568141cc406Sopenharmony_ci 569141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "Trying to clear the interrupt buffer...\n")); 570141cc406Sopenharmony_ci if (handle_interrupt (s, 200) == 0) 571141cc406Sopenharmony_ci { 572141cc406Sopenharmony_ci PDBG (pixma_dbg (3, " no packets in buffer\n")); 573141cc406Sopenharmony_ci } 574141cc406Sopenharmony_ci return 0; 575141cc406Sopenharmony_ci} 576141cc406Sopenharmony_ci 577141cc406Sopenharmony_cistatic void 578141cc406Sopenharmony_ciiclass_close (pixma_t * s) 579141cc406Sopenharmony_ci{ 580141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 581141cc406Sopenharmony_ci 582141cc406Sopenharmony_ci iclass_finish_scan (s); 583141cc406Sopenharmony_ci free (mf->cb.buf); 584141cc406Sopenharmony_ci free (mf->buf); 585141cc406Sopenharmony_ci free (mf); 586141cc406Sopenharmony_ci s->subdriver = NULL; 587141cc406Sopenharmony_ci} 588141cc406Sopenharmony_ci 589141cc406Sopenharmony_cistatic int 590141cc406Sopenharmony_ciiclass_check_param (pixma_t * s, pixma_scan_param_t * sp) 591141cc406Sopenharmony_ci{ 592141cc406Sopenharmony_ci UNUSED (s); 593141cc406Sopenharmony_ci 594141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*iclass_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, line_size=%" PRIu64 " , h=%u*****\n", 595141cc406Sopenharmony_ci sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->line_size, sp->h)); */ 596141cc406Sopenharmony_ci 597141cc406Sopenharmony_ci sp->depth = 8; 598141cc406Sopenharmony_ci sp->software_lineart = 0; 599141cc406Sopenharmony_ci if (sp->mode == PIXMA_SCAN_MODE_LINEART) 600141cc406Sopenharmony_ci { 601141cc406Sopenharmony_ci sp->software_lineart = 1; 602141cc406Sopenharmony_ci sp->channels = 1; 603141cc406Sopenharmony_ci sp->depth = 1; 604141cc406Sopenharmony_ci } 605141cc406Sopenharmony_ci 606141cc406Sopenharmony_ci if (sp->software_lineart == 1) 607141cc406Sopenharmony_ci { 608141cc406Sopenharmony_ci unsigned w_max; 609141cc406Sopenharmony_ci 610141cc406Sopenharmony_ci /* for software lineart line_size and w must be a multiple of 8 */ 611141cc406Sopenharmony_ci sp->line_size = ALIGN_SUP (sp->w, 8) * sp->channels; 612141cc406Sopenharmony_ci sp->w = ALIGN_SUP (sp->w, 8); 613141cc406Sopenharmony_ci 614141cc406Sopenharmony_ci /* do not exceed the scanner capability */ 615141cc406Sopenharmony_ci w_max = s->cfg->width * s->cfg->xdpi / 75; 616141cc406Sopenharmony_ci w_max -= w_max % 32; 617141cc406Sopenharmony_ci if (sp->w > w_max) 618141cc406Sopenharmony_ci sp->w = w_max; 619141cc406Sopenharmony_ci } 620141cc406Sopenharmony_ci else 621141cc406Sopenharmony_ci sp->line_size = ALIGN_SUP (sp->w, 32) * sp->channels; 622141cc406Sopenharmony_ci 623141cc406Sopenharmony_ci /* Some exceptions here for particular devices */ 624141cc406Sopenharmony_ci /* Those devices can scan up to Legal 14" with ADF, but A4 11.7" in flatbed */ 625141cc406Sopenharmony_ci /* PIXMA_CAP_ADF also works for PIXMA_CAP_ADFDUP */ 626141cc406Sopenharmony_ci if ((s->cfg->cap & PIXMA_CAP_ADF) && sp->source == PIXMA_SOURCE_FLATBED) 627141cc406Sopenharmony_ci sp->h = MIN (sp->h, 877 * sp->xdpi / 75); 628141cc406Sopenharmony_ci 629141cc406Sopenharmony_ci sp->mode_jpeg = (s->cfg->cap & PIXMA_CAP_JPEG); 630141cc406Sopenharmony_ci 631141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*iclass_check_param***** Finally: channels=%u, depth=%u, x=%u, y=%u, w=%u, line_size=%" PRIu64 " , h=%u*****\n", 632141cc406Sopenharmony_ci sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->line_size, sp->h)); */ 633141cc406Sopenharmony_ci 634141cc406Sopenharmony_ci return 0; 635141cc406Sopenharmony_ci} 636141cc406Sopenharmony_ci 637141cc406Sopenharmony_cistatic int 638141cc406Sopenharmony_ciiclass_scan (pixma_t * s) 639141cc406Sopenharmony_ci{ 640141cc406Sopenharmony_ci int error, n; 641141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 642141cc406Sopenharmony_ci uint8_t *buf, ignore; 643141cc406Sopenharmony_ci unsigned buf_len, ignore2; 644141cc406Sopenharmony_ci 645141cc406Sopenharmony_ci if (mf->state != state_idle) 646141cc406Sopenharmony_ci return PIXMA_EBUSY; 647141cc406Sopenharmony_ci 648141cc406Sopenharmony_ci /* clear interrupt packets buffer */ 649141cc406Sopenharmony_ci while (handle_interrupt (s, 0) > 0) 650141cc406Sopenharmony_ci { 651141cc406Sopenharmony_ci } 652141cc406Sopenharmony_ci 653141cc406Sopenharmony_ci mf->raw_width = ALIGN_SUP (s->param->w, 32); 654141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "raw_width = %u\n", mf->raw_width)); 655141cc406Sopenharmony_ci 656141cc406Sopenharmony_ci n = IMAGE_BLOCK_SIZE / s->param->line_size + 1; 657141cc406Sopenharmony_ci buf_len = (n + 1) * s->param->line_size + IMAGE_BLOCK_SIZE; 658141cc406Sopenharmony_ci if (buf_len > mf->buf_len) 659141cc406Sopenharmony_ci { 660141cc406Sopenharmony_ci buf = (uint8_t *) realloc (mf->buf, buf_len); 661141cc406Sopenharmony_ci if (!buf) 662141cc406Sopenharmony_ci return PIXMA_ENOMEM; 663141cc406Sopenharmony_ci mf->buf = buf; 664141cc406Sopenharmony_ci mf->buf_len = buf_len; 665141cc406Sopenharmony_ci } 666141cc406Sopenharmony_ci mf->lineptr = mf->buf; 667141cc406Sopenharmony_ci mf->blkptr = mf->buf + n * s->param->line_size; 668141cc406Sopenharmony_ci mf->blk_len = 0; 669141cc406Sopenharmony_ci 670141cc406Sopenharmony_ci error = step1 (s); 671141cc406Sopenharmony_ci if (error >= 0 672141cc406Sopenharmony_ci && (s->param->adf_pageid == 0 || mf->generation == 1 || mf->adf_state == state_idle)) 673141cc406Sopenharmony_ci { /* single sheet or first sheet from ADF */ 674141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "*iclass_scan***** start scanning *****\n")); 675141cc406Sopenharmony_ci error = start_session (s); 676141cc406Sopenharmony_ci if (error >= 0) 677141cc406Sopenharmony_ci mf->state = state_scanning; 678141cc406Sopenharmony_ci if (error >= 0) 679141cc406Sopenharmony_ci error = select_source (s); 680141cc406Sopenharmony_ci } 681141cc406Sopenharmony_ci else if (error >= 0) 682141cc406Sopenharmony_ci { /* next sheet from ADF */ 683141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "*iclass_scan***** scan next sheet from ADF *****\n")); 684141cc406Sopenharmony_ci mf->state = state_scanning; 685141cc406Sopenharmony_ci } 686141cc406Sopenharmony_ci if (error >= 0) 687141cc406Sopenharmony_ci error = send_scan_param (s); 688141cc406Sopenharmony_ci if (error >= 0) 689141cc406Sopenharmony_ci error = request_image_block (s, 0, &ignore, &ignore2, &ignore, &ignore2); 690141cc406Sopenharmony_ci if (error < 0) 691141cc406Sopenharmony_ci { 692141cc406Sopenharmony_ci iclass_finish_scan (s); 693141cc406Sopenharmony_ci return error; 694141cc406Sopenharmony_ci } 695141cc406Sopenharmony_ci mf->last_block = 0; 696141cc406Sopenharmony_ci 697141cc406Sopenharmony_ci /* ADF scanning active */ 698141cc406Sopenharmony_ci if (is_scanning_from_adf (s)) 699141cc406Sopenharmony_ci mf->adf_state = state_scanning; 700141cc406Sopenharmony_ci return 0; 701141cc406Sopenharmony_ci} 702141cc406Sopenharmony_ci 703141cc406Sopenharmony_ci 704141cc406Sopenharmony_cistatic int 705141cc406Sopenharmony_ciiclass_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) 706141cc406Sopenharmony_ci{ 707141cc406Sopenharmony_ci int error, n; 708141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 709141cc406Sopenharmony_ci unsigned block_size, lines_size, lineart_lines_size, first_block_size; 710141cc406Sopenharmony_ci uint8_t info; 711141cc406Sopenharmony_ci 712141cc406Sopenharmony_ci/* 713141cc406Sopenharmony_ci * 1. send a block request cmd (d4 20 00... 04 00 06) 714141cc406Sopenharmony_ci * 2. examine the response for block size and/or end-of-scan flag 715141cc406Sopenharmony_ci * 3. read the block one chunk at a time 716141cc406Sopenharmony_ci * 4. repeat until have enough to process >=1 lines 717141cc406Sopenharmony_ci */ 718141cc406Sopenharmony_ci do 719141cc406Sopenharmony_ci { 720141cc406Sopenharmony_ci do 721141cc406Sopenharmony_ci { 722141cc406Sopenharmony_ci if (s->cancel) 723141cc406Sopenharmony_ci return PIXMA_ECANCELED; 724141cc406Sopenharmony_ci if (mf->last_block) 725141cc406Sopenharmony_ci { 726141cc406Sopenharmony_ci /* end of image */ 727141cc406Sopenharmony_ci mf->state = state_finished; 728141cc406Sopenharmony_ci return 0; 729141cc406Sopenharmony_ci } 730141cc406Sopenharmony_ci 731141cc406Sopenharmony_ci first_block_size = 0; 732141cc406Sopenharmony_ci error = request_image_block (s, 4, &info, &block_size, 733141cc406Sopenharmony_ci mf->blkptr + mf->blk_len, &first_block_size); 734141cc406Sopenharmony_ci /* add current block to remainder of previous */ 735141cc406Sopenharmony_ci mf->blk_len += first_block_size; 736141cc406Sopenharmony_ci if (error < 0) 737141cc406Sopenharmony_ci { 738141cc406Sopenharmony_ci /* NOTE: seen in traffic logs but don't know the meaning. */ 739141cc406Sopenharmony_ci read_error_info (s, NULL, 0); 740141cc406Sopenharmony_ci if (error == PIXMA_ECANCELED) 741141cc406Sopenharmony_ci return error; 742141cc406Sopenharmony_ci } 743141cc406Sopenharmony_ci 744141cc406Sopenharmony_ci /* info: 0x28 = end; 0x38 = end + ADF empty */ 745141cc406Sopenharmony_ci mf->last_block = info & 0x38; 746141cc406Sopenharmony_ci if ((info & ~0x38) != 0) 747141cc406Sopenharmony_ci { 748141cc406Sopenharmony_ci PDBG (pixma_dbg (1, "WARNING: Unexpected result header\n")); 749141cc406Sopenharmony_ci PDBG (pixma_hexdump (1, &info, 1)); 750141cc406Sopenharmony_ci } 751141cc406Sopenharmony_ci 752141cc406Sopenharmony_ci if (block_size == 0) 753141cc406Sopenharmony_ci { 754141cc406Sopenharmony_ci /* no image data at this moment. */ 755141cc406Sopenharmony_ci /*pixma_sleep(100000); *//* FIXME: too short, too long? */ 756141cc406Sopenharmony_ci handle_interrupt (s, 100); 757141cc406Sopenharmony_ci } 758141cc406Sopenharmony_ci } 759141cc406Sopenharmony_ci while (block_size == 0 && first_block_size == 0); 760141cc406Sopenharmony_ci 761141cc406Sopenharmony_ci error = read_image_block (s, mf->blkptr + mf->blk_len, block_size); 762141cc406Sopenharmony_ci block_size = error; 763141cc406Sopenharmony_ci if (error < 0) 764141cc406Sopenharmony_ci return error; 765141cc406Sopenharmony_ci 766141cc406Sopenharmony_ci /* add current block to remainder of previous */ 767141cc406Sopenharmony_ci mf->blk_len += block_size; 768141cc406Sopenharmony_ci /* n = number of full lines (rows) we have in the buffer. */ 769141cc406Sopenharmony_ci n = mf->blk_len / ((s->param->mode == PIXMA_SCAN_MODE_LINEART) ? mf->raw_width : s->param->line_size); 770141cc406Sopenharmony_ci if (n != 0) 771141cc406Sopenharmony_ci { 772141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** Processing with n=%d, w=%i, line_size=%" PRIu64 ", raw_width=%u ***** \n", 773141cc406Sopenharmony_ci n, s->param->w, s->param->line_size, mf->raw_width)); */ 774141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** scan_mode=%d, lineptr=%" PRIu64 ", blkptr=%" PRIu64 " \n", 775141cc406Sopenharmony_ci s->param->mode, (uint64_t)mf->lineptr, (uint64_t)mf->blkptr)); */ 776141cc406Sopenharmony_ci 777141cc406Sopenharmony_ci /* gray to lineart convert 778141cc406Sopenharmony_ci * mf->lineptr : image line 779141cc406Sopenharmony_ci * mf->blkptr : scanned image block as grayscale 780141cc406Sopenharmony_ci * s->param->w : image width 781141cc406Sopenharmony_ci * s->param->line_size : scanned image width */ 782141cc406Sopenharmony_ci if (s->param->mode == PIXMA_SCAN_MODE_LINEART) 783141cc406Sopenharmony_ci { 784141cc406Sopenharmony_ci int i; 785141cc406Sopenharmony_ci uint8_t *sptr, *dptr; 786141cc406Sopenharmony_ci 787141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** Processing lineart *****\n")); */ 788141cc406Sopenharmony_ci 789141cc406Sopenharmony_ci /* process ALL lines */ 790141cc406Sopenharmony_ci sptr = mf->blkptr; 791141cc406Sopenharmony_ci dptr = mf->lineptr; 792141cc406Sopenharmony_ci for (i = 0; i < n; i++, sptr += mf->raw_width) 793141cc406Sopenharmony_ci dptr = pixma_binarize_line (s->param, dptr, sptr, s->param->line_size, 1); 794141cc406Sopenharmony_ci } 795141cc406Sopenharmony_ci else if (s->param->channels != 1 && 796141cc406Sopenharmony_ci mf->generation == 1 && 797141cc406Sopenharmony_ci s->cfg->pid != MF4600_PID && 798141cc406Sopenharmony_ci s->cfg->pid != MF6500_PID && 799141cc406Sopenharmony_ci s->cfg->pid != MF8030_PID && 800141cc406Sopenharmony_ci s->cfg->pid != IR1018_PID) 801141cc406Sopenharmony_ci { 802141cc406Sopenharmony_ci /* color and not MF46xx or MF65xx */ 803141cc406Sopenharmony_ci pack_rgb (mf->blkptr, n, mf->raw_width, mf->lineptr); 804141cc406Sopenharmony_ci } 805141cc406Sopenharmony_ci else 806141cc406Sopenharmony_ci { 807141cc406Sopenharmony_ci /* grayscale */ 808141cc406Sopenharmony_ci memcpy (mf->lineptr, mf->blkptr, n * s->param->line_size); 809141cc406Sopenharmony_ci } 810141cc406Sopenharmony_ci /* cull remainder and shift left */ 811141cc406Sopenharmony_ci lineart_lines_size = n * s->param->line_size / 8; 812141cc406Sopenharmony_ci lines_size = n * ((s->param->mode == PIXMA_SCAN_MODE_LINEART) ? mf->raw_width : s->param->line_size); 813141cc406Sopenharmony_ci mf->blk_len -= lines_size; 814141cc406Sopenharmony_ci memcpy (mf->blkptr, mf->blkptr + lines_size, mf->blk_len); 815141cc406Sopenharmony_ci } 816141cc406Sopenharmony_ci } 817141cc406Sopenharmony_ci while (n == 0); 818141cc406Sopenharmony_ci 819141cc406Sopenharmony_ci /* output full lines, keep partial lines for next block 820141cc406Sopenharmony_ci * ib->rptr : start of image buffer 821141cc406Sopenharmony_ci * ib->rend : end of image buffer */ 822141cc406Sopenharmony_ci ib->rptr = mf->lineptr; 823141cc406Sopenharmony_ci ib->rend = mf->lineptr + (s->param->mode == PIXMA_SCAN_MODE_LINEART ? lineart_lines_size : lines_size); 824141cc406Sopenharmony_ci /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** rptr=%" PRIu64 ", rend=%" PRIu64 ", diff=%ld \n", 825141cc406Sopenharmony_ci (uint64_t)ib->rptr, (uint64_t)ib->rend, ib->rend - ib->rptr)); */ 826141cc406Sopenharmony_ci return ib->rend - ib->rptr; 827141cc406Sopenharmony_ci} 828141cc406Sopenharmony_ci 829141cc406Sopenharmony_cistatic void 830141cc406Sopenharmony_ciiclass_finish_scan (pixma_t * s) 831141cc406Sopenharmony_ci{ 832141cc406Sopenharmony_ci int error; 833141cc406Sopenharmony_ci iclass_t *mf = (iclass_t *) s->subdriver; 834141cc406Sopenharmony_ci 835141cc406Sopenharmony_ci switch (mf->state) 836141cc406Sopenharmony_ci { 837141cc406Sopenharmony_ci /* fall through */ 838141cc406Sopenharmony_ci case state_warmup: 839141cc406Sopenharmony_ci case state_scanning: 840141cc406Sopenharmony_ci error = abort_session (s); 841141cc406Sopenharmony_ci if (error < 0) 842141cc406Sopenharmony_ci PDBG (pixma_dbg 843141cc406Sopenharmony_ci (1, "WARNING:abort_session() failed %s\n", 844141cc406Sopenharmony_ci pixma_strerror (error))); 845141cc406Sopenharmony_ci /* fall through */ 846141cc406Sopenharmony_ci case state_finished: 847141cc406Sopenharmony_ci query_status (s); 848141cc406Sopenharmony_ci query_status (s); 849141cc406Sopenharmony_ci if (mf->generation == 1) 850141cc406Sopenharmony_ci { /* activate only seen for generation 1 scanners */ 851141cc406Sopenharmony_ci activate (s, 0); 852141cc406Sopenharmony_ci query_status (s); 853141cc406Sopenharmony_ci } 854141cc406Sopenharmony_ci /* generation = 1: 855141cc406Sopenharmony_ci * 0x28 = last block (no multi page scan) 856141cc406Sopenharmony_ci * generation >= 2: 857141cc406Sopenharmony_ci * 0x38 = last block and ADF empty (generation >= 2) 858141cc406Sopenharmony_ci * 0x28 = last block and Paper in ADF (multi page scan) 859141cc406Sopenharmony_ci * some generation 2 scanners don't use 0x38 for ADF empty => check status */ 860141cc406Sopenharmony_ci if (mf->last_block==0x38 /* generation 2 scanner ADF empty */ 861141cc406Sopenharmony_ci || (mf->generation == 1 && mf->last_block == 0x28) /* generation 1 scanner last block */ 862141cc406Sopenharmony_ci || (mf->generation >= 2 && !has_paper(s))) /* check status: no paper in ADF */ 863141cc406Sopenharmony_ci { 864141cc406Sopenharmony_ci /* ADFDUP scan: wait for 8sec to throw last page out of ADF feeder */ 865141cc406Sopenharmony_ci if (is_scanning_from_adfdup(s)) 866141cc406Sopenharmony_ci { 867141cc406Sopenharmony_ci PDBG (pixma_dbg (4, "*iclass_finish_scan***** sleep for 8s *****\n")); 868141cc406Sopenharmony_ci pixma_sleep(8000000); /* sleep for 8s */ 869141cc406Sopenharmony_ci query_status (s); 870141cc406Sopenharmony_ci } 871141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "*iclass_finish_scan***** abort session *****\n")); 872141cc406Sopenharmony_ci abort_session (s); 873141cc406Sopenharmony_ci mf->adf_state = state_idle; 874141cc406Sopenharmony_ci mf->last_block = 0; 875141cc406Sopenharmony_ci } 876141cc406Sopenharmony_ci else 877141cc406Sopenharmony_ci PDBG (pixma_dbg (3, "*iclass_finish_scan***** wait for next page from ADF *****\n")); 878141cc406Sopenharmony_ci 879141cc406Sopenharmony_ci mf->state = state_idle; 880141cc406Sopenharmony_ci /* fall through */ 881141cc406Sopenharmony_ci case state_idle: 882141cc406Sopenharmony_ci break; 883141cc406Sopenharmony_ci } 884141cc406Sopenharmony_ci} 885141cc406Sopenharmony_ci 886141cc406Sopenharmony_cistatic void 887141cc406Sopenharmony_ciiclass_wait_event (pixma_t * s, int timeout) 888141cc406Sopenharmony_ci{ 889141cc406Sopenharmony_ci /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for 890141cc406Sopenharmony_ci * instance. */ 891141cc406Sopenharmony_ci while (s->events == 0 && handle_interrupt (s, timeout) > 0) 892141cc406Sopenharmony_ci { 893141cc406Sopenharmony_ci } 894141cc406Sopenharmony_ci} 895141cc406Sopenharmony_ci 896141cc406Sopenharmony_cistatic int 897141cc406Sopenharmony_ciiclass_get_status (pixma_t * s, pixma_device_status_t * status) 898141cc406Sopenharmony_ci{ 899141cc406Sopenharmony_ci int error; 900141cc406Sopenharmony_ci 901141cc406Sopenharmony_ci error = query_status (s); 902141cc406Sopenharmony_ci if (error < 0) 903141cc406Sopenharmony_ci return error; 904141cc406Sopenharmony_ci status->hardware = PIXMA_HARDWARE_OK; 905141cc406Sopenharmony_ci status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; 906141cc406Sopenharmony_ci return 0; 907141cc406Sopenharmony_ci} 908141cc406Sopenharmony_ci 909141cc406Sopenharmony_ci 910141cc406Sopenharmony_cistatic const pixma_scan_ops_t pixma_iclass_ops = { 911141cc406Sopenharmony_ci iclass_open, 912141cc406Sopenharmony_ci iclass_close, 913141cc406Sopenharmony_ci iclass_scan, 914141cc406Sopenharmony_ci iclass_fill_buffer, 915141cc406Sopenharmony_ci iclass_finish_scan, 916141cc406Sopenharmony_ci iclass_wait_event, 917141cc406Sopenharmony_ci iclass_check_param, 918141cc406Sopenharmony_ci iclass_get_status 919141cc406Sopenharmony_ci}; 920141cc406Sopenharmony_ci 921141cc406Sopenharmony_ci#define DEV(name, model, pid, dpi, adftpu_max_dpi, w, h, cap) { \ 922141cc406Sopenharmony_ci name, /* name */ \ 923141cc406Sopenharmony_ci model, /* model */ \ 924141cc406Sopenharmony_ci 0x04a9, pid, /* vid pid */ \ 925141cc406Sopenharmony_ci 1, /* iface */ \ 926141cc406Sopenharmony_ci &pixma_iclass_ops, /* ops */ \ 927141cc406Sopenharmony_ci 0, 0, /* min_xdpi & min_xdpi_16 not used in this subdriver */ \ 928141cc406Sopenharmony_ci dpi, dpi, /* xdpi, ydpi */ \ 929141cc406Sopenharmony_ci 0, /* adftpu_min_dpi not used in this subdriver */ \ 930141cc406Sopenharmony_ci adftpu_max_dpi, /* adftpu_max_dpi */ \ 931141cc406Sopenharmony_ci 0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \ 932141cc406Sopenharmony_ci w, h, /* width, height */ \ 933141cc406Sopenharmony_ci PIXMA_CAP_LINEART| /* all scanners have software lineart */ \ 934141cc406Sopenharmony_ci PIXMA_CAP_ADF_WAIT| /* adf wait for all ADF and ADFDUP scanners */ \ 935141cc406Sopenharmony_ci PIXMA_CAP_GRAY|PIXMA_CAP_EVENTS|cap \ 936141cc406Sopenharmony_ci} 937141cc406Sopenharmony_ciconst pixma_config_t pixma_iclass_devices[] = { 938141cc406Sopenharmony_ci DEV ("Canon imageCLASS MF4270", "MF4270", MF4200_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), 939141cc406Sopenharmony_ci DEV ("Canon imageCLASS MF4150", "MF4100", MF4100_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), 940141cc406Sopenharmony_ci DEV ("Canon imageCLASS MF4690", "MF4690", MF4600_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), 941141cc406Sopenharmony_ci DEV ("Canon imageCLASS D420", "D420", D420_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), 942141cc406Sopenharmony_ci DEV ("Canon imageCLASS D480", "D480", D480_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), 943141cc406Sopenharmony_ci DEV ("Canon imageCLASS MF4360", "MF4360", MF4360_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), 944141cc406Sopenharmony_ci DEV ("Canon imageCLASS MF4320", "MF4320", MF4320_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), 945141cc406Sopenharmony_ci DEV ("Canon imageCLASS MF4010", "MF4010", MF4010_PID, 600, 0, 640, 877, 0), 946141cc406Sopenharmony_ci DEV ("Canon imageCLASS MF3240", "MF3240", MF3200_PID, 600, 0, 640, 877, 0), 947141cc406Sopenharmony_ci DEV ("Canon imageClass MF6500", "MF6500", MF6500_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), 948141cc406Sopenharmony_ci DEV ("Canon imageCLASS MF4410", "MF4410", MF4410_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), 949141cc406Sopenharmony_ci DEV ("Canon imageCLASS D550", "D550", D550_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), 950141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF4500 Series", "MF4500", MF4500_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), 951141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF3010", "MF3010", MF3010_PID, 600, 0, 640, 877, 0), 952141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF4700 Series", "MF4700", MF4700_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), 953141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF4800 Series", "MF4800", MF4800_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), 954141cc406Sopenharmony_ci DEV ("Canon imageCLASS MF4570dw", "MF4570dw", MF4570_PID, 600, 0, 640, 877, 0), 955141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF8200C Series", "MF8200C", MF8200_PID, 600, 300, 640, 1050, PIXMA_CAP_ADF), 956141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF8300 Series", "MF8300", MF8300_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), 957141cc406Sopenharmony_ci DEV ("Canon imageCLASS D530", "D530", D530_PID, 600, 0, 640, 877, 0), 958141cc406Sopenharmony_ci DEV ("Canon imageRUNNER 1018/1022/1023", "iR1018/1022/1023", IR1018_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), 959141cc406Sopenharmony_ci /* FIXME: the following capabilities all need updating/verifying */ 960141cc406Sopenharmony_ci DEV ("Canon imageCLASS MF8170c", "MF8170c", MF8100_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), 961141cc406Sopenharmony_ci DEV ("Canon imageClass MF8030", "MF8030", MF8030_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), 962141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF5880dn", "MF5880", MF5880_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), 963141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF6680dn", "MF6680", MF6680_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), 964141cc406Sopenharmony_ci DEV ("Canon imageRUNNER 1133", "iR1133", IR1133_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ 965141cc406Sopenharmony_ci DEV ("Canon imageRUNNER 1133A", "imageRUNNER1133", IR1133_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ 966141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF5900 Series", "MF5900", MF5900_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), 967141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF8500C Series", "MF8500C", MF8500_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), 968141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF6100 Series", "MF6100", MF6100_PID, 600, 300, 640, 1050, PIXMA_CAP_ADFDUP), 969141cc406Sopenharmony_ci DEV ("Canon imageClass MF810/820", "MF810/820", MF820_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), 970141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF220 Series", "MF220", MF220_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ 971141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF210 Series", "MF210", MF210_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), /* max. w = 216mm */ 972141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF620 Series", "MF620", MF620_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), 973141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF720 Series", "MF720", MF720_PID, 600, 300, 637, 877, PIXMA_CAP_ADFDUP), 974141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF410 Series", "MF410", MF410_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ 975141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF510 Series", "MF510", MF510_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), 976141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF230 Series", "MF230", MF230_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), /* max. w = 216mm */ 977141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF240 Series", "MF240", MF240_PID, 600, 300, 634, 1050, PIXMA_CAP_ADF), /* max. w = 215mm, */ 978141cc406Sopenharmony_ci /* TODO: fix black stripes for 216mm @ 600dpi */ 979141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF630 Series", "MF630", MF630_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), 980141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF730 Series", "MF730", MF730_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), 981141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF731C", "MF731", MF731_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), 982141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF633C/MF635C", "MF633C/635C", MF630_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ 983141cc406Sopenharmony_ci DEV ("Canon imageCLASS MF634C", "MF632C/634C", MF634_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), 984141cc406Sopenharmony_ci DEV ("Canon imageCLASS MF733C", "MF731C/733C", MF731_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* however, we need this for ethernet/wifi */ 985141cc406Sopenharmony_ci DEV ("Canon imageCLASS D570", "D570", D570_PID, 600, 0, 640, 877, 0), 986141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF110/910 Series", "MF110", MF110_PID, 600, 0, 640, 1050, 0), 987141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF520 Series", "MF520", MF520_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), 988141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF420 Series", "MF420", MF420_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), 989141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF260 Series", "MF260", MF260_PID, 600, 0, 640, 1050, PIXMA_CAP_JPEG | PIXMA_CAP_ADFDUP), 990141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF740 Series", "MF740", MF740_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), 991141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF741C/743C", "MF741C/743C", MF743_PID, 600, 300, 640, 1050, PIXMA_CAP_ADFDUP), /* ADFDUP restricted to 300dpi */ 992141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF640 Series", "MF642C/643C/644C", MF640_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), 993141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF645C", "MF645C", MF645_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ 994141cc406Sopenharmony_ci DEV ("Canon i-SENSYS MF440 Series", "MF440", MF440_PID, 600, 300, 637, 877, PIXMA_CAP_ADFDUP), 995141cc406Sopenharmony_ci DEV (NULL, NULL, 0, 0, 0, 0, 0, 0) 996141cc406Sopenharmony_ci}; 997