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