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-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org>
5141cc406Sopenharmony_ci   Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>
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#include "../include/sane/config.h"
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_ci#include <stdio.h>
46141cc406Sopenharmony_ci#include <stdlib.h>
47141cc406Sopenharmony_ci#include <string.h>
48141cc406Sopenharmony_ci#include <time.h>		/* localtime(C90) */
49141cc406Sopenharmony_ci
50141cc406Sopenharmony_ci#include "pixma_rename.h"
51141cc406Sopenharmony_ci#include "pixma_common.h"
52141cc406Sopenharmony_ci#include "pixma_io.h"
53141cc406Sopenharmony_ci
54141cc406Sopenharmony_ci
55141cc406Sopenharmony_ci#ifdef __GNUC__
56141cc406Sopenharmony_ci# define UNUSED(v) (void) v
57141cc406Sopenharmony_ci#else
58141cc406Sopenharmony_ci# define UNUSED(v)
59141cc406Sopenharmony_ci#endif
60141cc406Sopenharmony_ci
61141cc406Sopenharmony_ci#define IMAGE_BLOCK_SIZE (0xc000)
62141cc406Sopenharmony_ci#define CMDBUF_SIZE 512
63141cc406Sopenharmony_ci
64141cc406Sopenharmony_ci#define MP10_PID 0x261f
65141cc406Sopenharmony_ci
66141cc406Sopenharmony_ci#define MP730_PID 0x262f
67141cc406Sopenharmony_ci#define MP700_PID 0x2630
68141cc406Sopenharmony_ci
69141cc406Sopenharmony_ci#define MP5_PID 0x2635          /* untested */
70141cc406Sopenharmony_ci
71141cc406Sopenharmony_ci#define MP360_PID 0x263c
72141cc406Sopenharmony_ci#define MP370_PID 0x263d
73141cc406Sopenharmony_ci#define MP390_PID 0x263e
74141cc406Sopenharmony_ci#define MP375R_PID 0x263f       /* untested */
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_ci#define MP740_PID 0x264c	/* Untested */
77141cc406Sopenharmony_ci#define MP710_PID 0x264d
78141cc406Sopenharmony_ci
79141cc406Sopenharmony_ci#define MF5630_PID 0x264e	/* Untested */
80141cc406Sopenharmony_ci#define MF5650_PID 0x264f
81141cc406Sopenharmony_ci#define MF5730_PID 0x265d	/* Untested */
82141cc406Sopenharmony_ci#define MF5750_PID 0x265e	/* Untested */
83141cc406Sopenharmony_ci#define MF5770_PID 0x265f
84141cc406Sopenharmony_ci#define MF3110_PID 0x2660
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_ci#define IR1020_PID 0x26e6
87141cc406Sopenharmony_ci
88141cc406Sopenharmony_cienum mp730_state_t
89141cc406Sopenharmony_ci{
90141cc406Sopenharmony_ci  state_idle,
91141cc406Sopenharmony_ci  state_warmup,
92141cc406Sopenharmony_ci  state_scanning,
93141cc406Sopenharmony_ci  state_transfering,
94141cc406Sopenharmony_ci  state_finished
95141cc406Sopenharmony_ci};
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_cienum mp730_cmd_t
98141cc406Sopenharmony_ci{
99141cc406Sopenharmony_ci  cmd_start_session = 0xdb20,
100141cc406Sopenharmony_ci  cmd_select_source = 0xdd20,
101141cc406Sopenharmony_ci  cmd_gamma         = 0xee20,
102141cc406Sopenharmony_ci  cmd_scan_param    = 0xde20,
103141cc406Sopenharmony_ci  cmd_status        = 0xf320,
104141cc406Sopenharmony_ci  cmd_abort_session = 0xef20,
105141cc406Sopenharmony_ci  cmd_time          = 0xeb80,
106141cc406Sopenharmony_ci  cmd_read_image    = 0xd420,
107141cc406Sopenharmony_ci  cmd_error_info    = 0xff20,
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_ci  cmd_activate      = 0xcf60,
110141cc406Sopenharmony_ci  cmd_calibrate     = 0xe920
111141cc406Sopenharmony_ci};
112141cc406Sopenharmony_ci
113141cc406Sopenharmony_citypedef struct mp730_t
114141cc406Sopenharmony_ci{
115141cc406Sopenharmony_ci  enum mp730_state_t state;
116141cc406Sopenharmony_ci  pixma_cmdbuf_t cb;
117141cc406Sopenharmony_ci  unsigned raw_width;
118141cc406Sopenharmony_ci  uint8_t current_status[12];
119141cc406Sopenharmony_ci
120141cc406Sopenharmony_ci  uint8_t *buf, *imgbuf, *lbuf;
121141cc406Sopenharmony_ci  unsigned imgbuf_len;
122141cc406Sopenharmony_ci
123141cc406Sopenharmony_ci  unsigned last_block:1;
124141cc406Sopenharmony_ci} mp730_t;
125141cc406Sopenharmony_ci
126141cc406Sopenharmony_ci
127141cc406Sopenharmony_cistatic void mp730_finish_scan (pixma_t * s);
128141cc406Sopenharmony_ci
129141cc406Sopenharmony_cistatic int
130141cc406Sopenharmony_cihas_paper (pixma_t * s)
131141cc406Sopenharmony_ci{
132141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
133141cc406Sopenharmony_ci  return (mp->current_status[1] == 0);
134141cc406Sopenharmony_ci}
135141cc406Sopenharmony_ci
136141cc406Sopenharmony_cistatic void
137141cc406Sopenharmony_cidrain_bulk_in (pixma_t * s)
138141cc406Sopenharmony_ci{
139141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
140141cc406Sopenharmony_ci  while (pixma_read (s->io, mp->imgbuf, IMAGE_BLOCK_SIZE) >= 0);
141141cc406Sopenharmony_ci}
142141cc406Sopenharmony_ci
143141cc406Sopenharmony_cistatic int
144141cc406Sopenharmony_ciabort_session (pixma_t * s)
145141cc406Sopenharmony_ci{
146141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
147141cc406Sopenharmony_ci  return pixma_exec_short_cmd (s, &mp->cb, cmd_abort_session);
148141cc406Sopenharmony_ci}
149141cc406Sopenharmony_ci
150141cc406Sopenharmony_cistatic int
151141cc406Sopenharmony_ciquery_status (pixma_t * s)
152141cc406Sopenharmony_ci{
153141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
154141cc406Sopenharmony_ci  uint8_t *data;
155141cc406Sopenharmony_ci  int error;
156141cc406Sopenharmony_ci
157141cc406Sopenharmony_ci  data = pixma_newcmd (&mp->cb, cmd_status, 0, 12);
158141cc406Sopenharmony_ci  error = pixma_exec (s, &mp->cb);
159141cc406Sopenharmony_ci  if (error >= 0)
160141cc406Sopenharmony_ci    {
161141cc406Sopenharmony_ci      memcpy (mp->current_status, data, 12);
162141cc406Sopenharmony_ci      PDBG (pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u\n",
163141cc406Sopenharmony_ci		       data[1], data[8], data[7]));
164141cc406Sopenharmony_ci    }
165141cc406Sopenharmony_ci  return error;
166141cc406Sopenharmony_ci}
167141cc406Sopenharmony_ci
168141cc406Sopenharmony_cistatic int
169141cc406Sopenharmony_ciactivate (pixma_t * s, uint8_t x)
170141cc406Sopenharmony_ci{
171141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
172141cc406Sopenharmony_ci  uint8_t *data = pixma_newcmd (&mp->cb, cmd_activate, 10, 0);
173141cc406Sopenharmony_ci  data[0] = 1;
174141cc406Sopenharmony_ci  data[3] = x;
175141cc406Sopenharmony_ci  return pixma_exec (s, &mp->cb);
176141cc406Sopenharmony_ci}
177141cc406Sopenharmony_ci
178141cc406Sopenharmony_cistatic int
179141cc406Sopenharmony_cistart_session (pixma_t * s)
180141cc406Sopenharmony_ci{
181141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
182141cc406Sopenharmony_ci  return pixma_exec_short_cmd (s, &mp->cb, cmd_start_session);
183141cc406Sopenharmony_ci}
184141cc406Sopenharmony_ci
185141cc406Sopenharmony_cistatic int
186141cc406Sopenharmony_ciselect_source (pixma_t * s)
187141cc406Sopenharmony_ci{
188141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
189141cc406Sopenharmony_ci  uint8_t *data = pixma_newcmd (&mp->cb, cmd_select_source, 10, 0);
190141cc406Sopenharmony_ci  switch (s->param->source)
191141cc406Sopenharmony_ci    {
192141cc406Sopenharmony_ci    case PIXMA_SOURCE_ADF:
193141cc406Sopenharmony_ci      data[0] = 2;
194141cc406Sopenharmony_ci      break;
195141cc406Sopenharmony_ci
196141cc406Sopenharmony_ci    case PIXMA_SOURCE_ADFDUP:
197141cc406Sopenharmony_ci      data[0] = 2;
198141cc406Sopenharmony_ci      data[5] = 3;
199141cc406Sopenharmony_ci      break;
200141cc406Sopenharmony_ci
201141cc406Sopenharmony_ci    default:
202141cc406Sopenharmony_ci      data[0] = 1;
203141cc406Sopenharmony_ci      break;
204141cc406Sopenharmony_ci    }
205141cc406Sopenharmony_ci  return pixma_exec (s, &mp->cb);
206141cc406Sopenharmony_ci}
207141cc406Sopenharmony_ci
208141cc406Sopenharmony_cistatic int
209141cc406Sopenharmony_cisend_scan_param (pixma_t * s)
210141cc406Sopenharmony_ci{
211141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
212141cc406Sopenharmony_ci  uint8_t *data;
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_ci  data = pixma_newcmd (&mp->cb, cmd_scan_param, 0x2e, 0);
215141cc406Sopenharmony_ci  pixma_set_be16 (s->param->xdpi | 0x1000, data + 0x04);
216141cc406Sopenharmony_ci  pixma_set_be16 (s->param->ydpi | 0x1000, data + 0x06);
217141cc406Sopenharmony_ci  pixma_set_be32 (s->param->x, data + 0x08);
218141cc406Sopenharmony_ci  pixma_set_be32 (s->param->y, data + 0x0c);
219141cc406Sopenharmony_ci  pixma_set_be32 (mp->raw_width, data + 0x10);
220141cc406Sopenharmony_ci  pixma_set_be32 (s->param->h, data + 0x14);
221141cc406Sopenharmony_ci
222141cc406Sopenharmony_ci  if (s->param->channels == 1)
223141cc406Sopenharmony_ci    {
224141cc406Sopenharmony_ci      if (s->param->depth == 1)
225141cc406Sopenharmony_ci        data[0x18] = 0x01;
226141cc406Sopenharmony_ci      else
227141cc406Sopenharmony_ci        data[0x18] = 0x04;
228141cc406Sopenharmony_ci    }
229141cc406Sopenharmony_ci  else
230141cc406Sopenharmony_ci    data[0x18] = 0x08;
231141cc406Sopenharmony_ci
232141cc406Sopenharmony_ci  data[0x19] = s->param->channels * s->param->depth;  /* bits per pixel, for lineart should be 0x01 */
233141cc406Sopenharmony_ci  data[0x1e] = (s->param->depth == 1) ? 0x80 : 0x00;  /* modify for lineart: 0x80 NEW */
234141cc406Sopenharmony_ci  data[0x1f] = (s->param->depth == 1) ? 0x80 : 0x7f;  /* modify for lineart: 0x80 */
235141cc406Sopenharmony_ci  data[0x20] = (s->param->depth == 1) ? 0x01 : 0xff;  /* modify for lineart: 0x01 */
236141cc406Sopenharmony_ci  data[0x23] = 0x81;
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_ci  return pixma_exec (s, &mp->cb);
239141cc406Sopenharmony_ci}
240141cc406Sopenharmony_ci
241141cc406Sopenharmony_cistatic int
242141cc406Sopenharmony_cicalibrate (pixma_t * s)
243141cc406Sopenharmony_ci{
244141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
245141cc406Sopenharmony_ci  return pixma_exec_short_cmd (s, &mp->cb, cmd_calibrate);
246141cc406Sopenharmony_ci}
247141cc406Sopenharmony_ci
248141cc406Sopenharmony_cistatic int
249141cc406Sopenharmony_ciread_image_block (pixma_t * s, uint8_t * header, uint8_t * data)
250141cc406Sopenharmony_ci{
251141cc406Sopenharmony_ci  static const uint8_t cmd[10] =	/* 0xd420 cmd */
252141cc406Sopenharmony_ci  { 0xd4, 0x20, 0, 0, 0, 0, 0, IMAGE_BLOCK_SIZE / 256, 4, 0 };
253141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
254141cc406Sopenharmony_ci  const int hlen = 2 + 4;
255141cc406Sopenharmony_ci  int error, datalen;
256141cc406Sopenharmony_ci
257141cc406Sopenharmony_ci  mp->state = state_transfering;
258141cc406Sopenharmony_ci  mp->cb.reslen =
259141cc406Sopenharmony_ci    pixma_cmd_transaction (s, cmd, sizeof (cmd), mp->cb.buf, 512);
260141cc406Sopenharmony_ci  datalen = mp->cb.reslen;
261141cc406Sopenharmony_ci  if (datalen < 0)
262141cc406Sopenharmony_ci    return datalen;
263141cc406Sopenharmony_ci
264141cc406Sopenharmony_ci  memcpy (header, mp->cb.buf, hlen);
265141cc406Sopenharmony_ci  if (datalen >= hlen)
266141cc406Sopenharmony_ci    {
267141cc406Sopenharmony_ci      datalen -= hlen;
268141cc406Sopenharmony_ci      memcpy (data, mp->cb.buf + hlen, datalen);
269141cc406Sopenharmony_ci      data += datalen;
270141cc406Sopenharmony_ci      if (mp->cb.reslen == 512)
271141cc406Sopenharmony_ci	{
272141cc406Sopenharmony_ci	  error = pixma_read (s->io, data, IMAGE_BLOCK_SIZE - 512 + hlen);
273141cc406Sopenharmony_ci	  if (error < 0)
274141cc406Sopenharmony_ci	    return error;
275141cc406Sopenharmony_ci	  datalen += error;
276141cc406Sopenharmony_ci	}
277141cc406Sopenharmony_ci    }
278141cc406Sopenharmony_ci
279141cc406Sopenharmony_ci  mp->state = state_scanning;
280141cc406Sopenharmony_ci  mp->cb.expected_reslen = 0;
281141cc406Sopenharmony_ci  error = pixma_check_result (&mp->cb);
282141cc406Sopenharmony_ci  if (error < 0)
283141cc406Sopenharmony_ci    return error;
284141cc406Sopenharmony_ci  if (mp->cb.reslen < hlen)
285141cc406Sopenharmony_ci    return PIXMA_EPROTO;
286141cc406Sopenharmony_ci  return datalen;
287141cc406Sopenharmony_ci}
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_cistatic int
290141cc406Sopenharmony_cisend_time (pixma_t * s)
291141cc406Sopenharmony_ci{
292141cc406Sopenharmony_ci  /* Why does a scanner need a time? */
293141cc406Sopenharmony_ci  time_t now;
294141cc406Sopenharmony_ci  struct tm *t;
295141cc406Sopenharmony_ci  uint8_t *data;
296141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
297141cc406Sopenharmony_ci
298141cc406Sopenharmony_ci  data = pixma_newcmd (&mp->cb, cmd_time, 20, 0);
299141cc406Sopenharmony_ci  pixma_get_time (&now, NULL);
300141cc406Sopenharmony_ci  t = localtime (&now);
301141cc406Sopenharmony_ci  strftime ((char *) data, 16, "%y/%m/%d %H:%M", t);
302141cc406Sopenharmony_ci  PDBG (pixma_dbg (3, "Sending time: '%s'\n", (char *) data));
303141cc406Sopenharmony_ci  return pixma_exec (s, &mp->cb);
304141cc406Sopenharmony_ci}
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_cistatic int
307141cc406Sopenharmony_cihandle_interrupt (pixma_t * s, int timeout)
308141cc406Sopenharmony_ci{
309141cc406Sopenharmony_ci  uint8_t buf[16];
310141cc406Sopenharmony_ci  int len;
311141cc406Sopenharmony_ci
312141cc406Sopenharmony_ci  len = pixma_wait_interrupt (s->io, buf, sizeof (buf), timeout);
313141cc406Sopenharmony_ci  if (len == PIXMA_ETIMEDOUT)
314141cc406Sopenharmony_ci    return 0;
315141cc406Sopenharmony_ci  if (len < 0)
316141cc406Sopenharmony_ci    return len;
317141cc406Sopenharmony_ci  switch (s->cfg->pid)
318141cc406Sopenharmony_ci    {
319141cc406Sopenharmony_ci    case MP360_PID:
320141cc406Sopenharmony_ci    case MP370_PID:
321141cc406Sopenharmony_ci    case MP375R_PID:
322141cc406Sopenharmony_ci    case MP390_PID:
323141cc406Sopenharmony_ci    case MF5630_PID:
324141cc406Sopenharmony_ci    case MF5650_PID:
325141cc406Sopenharmony_ci    case MF5730_PID:
326141cc406Sopenharmony_ci    case MF5750_PID:
327141cc406Sopenharmony_ci    case MF5770_PID:
328141cc406Sopenharmony_ci    case MF3110_PID:
329141cc406Sopenharmony_ci    case IR1020_PID:
330141cc406Sopenharmony_ci      if (len != 16)
331141cc406Sopenharmony_ci	{
332141cc406Sopenharmony_ci	  PDBG (pixma_dbg
333141cc406Sopenharmony_ci		(1, "WARNING:unexpected interrupt packet length %d\n", len));
334141cc406Sopenharmony_ci	  return PIXMA_EPROTO;
335141cc406Sopenharmony_ci	}
336141cc406Sopenharmony_ci      if (buf[12] & 0x40)
337141cc406Sopenharmony_ci	query_status (s);
338141cc406Sopenharmony_ci      if (buf[10] & 0x40)
339141cc406Sopenharmony_ci	send_time (s);
340141cc406Sopenharmony_ci      /* FIXME: following is unverified! */
341141cc406Sopenharmony_ci      if (buf[15] & 1)
342141cc406Sopenharmony_ci	s->events = PIXMA_EV_BUTTON2;	/* b/w scan */
343141cc406Sopenharmony_ci      if (buf[15] & 2)
344141cc406Sopenharmony_ci	s->events = PIXMA_EV_BUTTON1;	/* color scan */
345141cc406Sopenharmony_ci      break;
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci    case MP5_PID:
348141cc406Sopenharmony_ci    case MP10_PID:
349141cc406Sopenharmony_ci    case MP700_PID:
350141cc406Sopenharmony_ci    case MP730_PID:
351141cc406Sopenharmony_ci    case MP710_PID:
352141cc406Sopenharmony_ci    case MP740_PID:
353141cc406Sopenharmony_ci      if (len != 8)
354141cc406Sopenharmony_ci	{
355141cc406Sopenharmony_ci	  PDBG (pixma_dbg
356141cc406Sopenharmony_ci		(1, "WARNING:unexpected interrupt packet length %d\n", len));
357141cc406Sopenharmony_ci	  return PIXMA_EPROTO;
358141cc406Sopenharmony_ci	}
359141cc406Sopenharmony_ci      if (buf[7] & 0x10)
360141cc406Sopenharmony_ci	s->events = PIXMA_EV_BUTTON1;
361141cc406Sopenharmony_ci      if (buf[5] & 8)
362141cc406Sopenharmony_ci	send_time (s);
363141cc406Sopenharmony_ci      break;
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci    default:
366141cc406Sopenharmony_ci      PDBG (pixma_dbg (1, "WARNING:unknown interrupt, please report!\n"));
367141cc406Sopenharmony_ci      PDBG (pixma_hexdump (1, buf, len));
368141cc406Sopenharmony_ci    }
369141cc406Sopenharmony_ci  return 1;
370141cc406Sopenharmony_ci}
371141cc406Sopenharmony_ci
372141cc406Sopenharmony_cistatic int
373141cc406Sopenharmony_cihas_ccd_sensor (pixma_t * s)
374141cc406Sopenharmony_ci{
375141cc406Sopenharmony_ci  return (s->cfg->pid == MP360_PID ||
376141cc406Sopenharmony_ci          s->cfg->pid == MP370_PID ||
377141cc406Sopenharmony_ci          s->cfg->pid == MP375R_PID ||
378141cc406Sopenharmony_ci          s->cfg->pid == MP390_PID ||
379141cc406Sopenharmony_ci          s->cfg->pid == MF5630_PID ||
380141cc406Sopenharmony_ci          s->cfg->pid == MF5650_PID ||
381141cc406Sopenharmony_ci          s->cfg->pid == MF5730_PID ||
382141cc406Sopenharmony_ci          s->cfg->pid == MF5750_PID ||
383141cc406Sopenharmony_ci          s->cfg->pid == MF5770_PID);
384141cc406Sopenharmony_ci}
385141cc406Sopenharmony_ci
386141cc406Sopenharmony_cistatic int
387141cc406Sopenharmony_ciread_error_info (pixma_t * s, void *buf, unsigned size)
388141cc406Sopenharmony_ci{
389141cc406Sopenharmony_ci  unsigned len = 16;
390141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
391141cc406Sopenharmony_ci  uint8_t *data;
392141cc406Sopenharmony_ci  int error;
393141cc406Sopenharmony_ci
394141cc406Sopenharmony_ci  data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len);
395141cc406Sopenharmony_ci  error = pixma_exec (s, &mp->cb);
396141cc406Sopenharmony_ci  if (error < 0)
397141cc406Sopenharmony_ci    return error;
398141cc406Sopenharmony_ci  if (buf && len < size)
399141cc406Sopenharmony_ci    {
400141cc406Sopenharmony_ci      size = len;
401141cc406Sopenharmony_ci      /* NOTE: I've absolutely no idea what the returned data mean. */
402141cc406Sopenharmony_ci      memcpy (buf, data, size);
403141cc406Sopenharmony_ci      error = len;
404141cc406Sopenharmony_ci    }
405141cc406Sopenharmony_ci  return error;
406141cc406Sopenharmony_ci}
407141cc406Sopenharmony_ci
408141cc406Sopenharmony_cistatic int
409141cc406Sopenharmony_cistep1 (pixma_t * s)
410141cc406Sopenharmony_ci{
411141cc406Sopenharmony_ci  int error;
412141cc406Sopenharmony_ci
413141cc406Sopenharmony_ci  error = query_status (s);
414141cc406Sopenharmony_ci  if (error < 0)
415141cc406Sopenharmony_ci    return error;
416141cc406Sopenharmony_ci  if ((s->param->source == PIXMA_SOURCE_ADF
417141cc406Sopenharmony_ci       || s->param->source == PIXMA_SOURCE_ADFDUP)
418141cc406Sopenharmony_ci      && !has_paper (s))
419141cc406Sopenharmony_ci    return PIXMA_ENO_PAPER;
420141cc406Sopenharmony_ci  if (has_ccd_sensor (s))
421141cc406Sopenharmony_ci    {
422141cc406Sopenharmony_ci      switch (s->cfg->pid)
423141cc406Sopenharmony_ci        {
424141cc406Sopenharmony_ci          case MF5630_PID:
425141cc406Sopenharmony_ci          case MF5650_PID:
426141cc406Sopenharmony_ci          case MF5730_PID:
427141cc406Sopenharmony_ci          case MF5750_PID:
428141cc406Sopenharmony_ci          case MF5770_PID:
429141cc406Sopenharmony_ci          /* MF57x0: Wait 10 sec before starting for 1st page only */
430141cc406Sopenharmony_ci            if (s->param->adf_pageid == 0)
431141cc406Sopenharmony_ci	      {
432141cc406Sopenharmony_ci                int tmo = 10;  /* like Windows driver, 10 sec CCD calibration ? */
433141cc406Sopenharmony_ci                while (--tmo >= 0)
434141cc406Sopenharmony_ci                  {
435141cc406Sopenharmony_ci                    error = handle_interrupt (s, 1000);
436141cc406Sopenharmony_ci                    if (s->cancel)
437141cc406Sopenharmony_ci                      return PIXMA_ECANCELED;
438141cc406Sopenharmony_ci                    if (error != PIXMA_ECANCELED && error < 0)
439141cc406Sopenharmony_ci                      return error;
440141cc406Sopenharmony_ci                    PDBG (pixma_dbg (2, "CCD Calibration ends in %d sec.\n", tmo));
441141cc406Sopenharmony_ci                  }
442141cc406Sopenharmony_ci              }
443141cc406Sopenharmony_ci            break;
444141cc406Sopenharmony_ci
445141cc406Sopenharmony_ci          default:
446141cc406Sopenharmony_ci            break;
447141cc406Sopenharmony_ci        }
448141cc406Sopenharmony_ci
449141cc406Sopenharmony_ci      activate (s, 0);
450141cc406Sopenharmony_ci      error = calibrate (s);
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci      switch (s->cfg->pid)
453141cc406Sopenharmony_ci        {
454141cc406Sopenharmony_ci          case MF5630_PID:
455141cc406Sopenharmony_ci          case MF5650_PID:
456141cc406Sopenharmony_ci          case MF5730_PID:
457141cc406Sopenharmony_ci          case MF5750_PID:
458141cc406Sopenharmony_ci          case MF5770_PID:
459141cc406Sopenharmony_ci          /* MF57x0: calibration returns PIXMA_STATUS_FAILED */
460141cc406Sopenharmony_ci            if (error == PIXMA_ECANCELED)
461141cc406Sopenharmony_ci              error = read_error_info (s, NULL, 0);
462141cc406Sopenharmony_ci            break;
463141cc406Sopenharmony_ci
464141cc406Sopenharmony_ci          default:
465141cc406Sopenharmony_ci            break;
466141cc406Sopenharmony_ci        }
467141cc406Sopenharmony_ci
468141cc406Sopenharmony_ci      // ignore result from calibrate()
469141cc406Sopenharmony_ci      // don't interrupt @ PIXMA_STATUS_BUSY
470141cc406Sopenharmony_ci      error = 0;
471141cc406Sopenharmony_ci    }
472141cc406Sopenharmony_ci  if (error >= 0)
473141cc406Sopenharmony_ci    error = activate (s, 0);
474141cc406Sopenharmony_ci  if (error >= 0)
475141cc406Sopenharmony_ci    error = activate (s, 4);
476141cc406Sopenharmony_ci  return error;
477141cc406Sopenharmony_ci}
478141cc406Sopenharmony_ci
479141cc406Sopenharmony_cistatic void
480141cc406Sopenharmony_cipack_rgb (const uint8_t * src, unsigned nlines, unsigned w, uint8_t * dst)
481141cc406Sopenharmony_ci{
482141cc406Sopenharmony_ci  unsigned w2, stride;
483141cc406Sopenharmony_ci
484141cc406Sopenharmony_ci  w2 = 2 * w;
485141cc406Sopenharmony_ci  stride = 3 * w;
486141cc406Sopenharmony_ci  for (; nlines != 0; nlines--)
487141cc406Sopenharmony_ci    {
488141cc406Sopenharmony_ci      unsigned x;
489141cc406Sopenharmony_ci      for (x = 0; x != w; x++)
490141cc406Sopenharmony_ci	{
491141cc406Sopenharmony_ci	  *dst++ = src[x + 0];
492141cc406Sopenharmony_ci	  *dst++ = src[x + w];
493141cc406Sopenharmony_ci	  *dst++ = src[x + w2];
494141cc406Sopenharmony_ci	}
495141cc406Sopenharmony_ci      src += stride;
496141cc406Sopenharmony_ci    }
497141cc406Sopenharmony_ci}
498141cc406Sopenharmony_ci
499141cc406Sopenharmony_cistatic int
500141cc406Sopenharmony_cimp730_open (pixma_t * s)
501141cc406Sopenharmony_ci{
502141cc406Sopenharmony_ci  mp730_t *mp;
503141cc406Sopenharmony_ci  uint8_t *buf;
504141cc406Sopenharmony_ci
505141cc406Sopenharmony_ci  mp = (mp730_t *) calloc (1, sizeof (*mp));
506141cc406Sopenharmony_ci  if (!mp)
507141cc406Sopenharmony_ci    return PIXMA_ENOMEM;
508141cc406Sopenharmony_ci
509141cc406Sopenharmony_ci  buf = (uint8_t *) malloc (CMDBUF_SIZE);
510141cc406Sopenharmony_ci  if (!buf)
511141cc406Sopenharmony_ci    {
512141cc406Sopenharmony_ci      free (mp);
513141cc406Sopenharmony_ci      return PIXMA_ENOMEM;
514141cc406Sopenharmony_ci    }
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci  s->subdriver = mp;
517141cc406Sopenharmony_ci  mp->state = state_idle;
518141cc406Sopenharmony_ci
519141cc406Sopenharmony_ci  mp->cb.buf = buf;
520141cc406Sopenharmony_ci  mp->cb.size = CMDBUF_SIZE;
521141cc406Sopenharmony_ci  mp->cb.res_header_len = 2;
522141cc406Sopenharmony_ci  mp->cb.cmd_header_len = 10;
523141cc406Sopenharmony_ci  mp->cb.cmd_len_field_ofs = 7;
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci  PDBG (pixma_dbg (3, "Trying to clear the interrupt buffer...\n"));
526141cc406Sopenharmony_ci  if (handle_interrupt (s, 200) == 0)
527141cc406Sopenharmony_ci    {
528141cc406Sopenharmony_ci      PDBG (pixma_dbg (3, "  no packets in buffer\n"));
529141cc406Sopenharmony_ci    }
530141cc406Sopenharmony_ci  return 0;
531141cc406Sopenharmony_ci}
532141cc406Sopenharmony_ci
533141cc406Sopenharmony_cistatic void
534141cc406Sopenharmony_cimp730_close (pixma_t * s)
535141cc406Sopenharmony_ci{
536141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
537141cc406Sopenharmony_ci
538141cc406Sopenharmony_ci  mp730_finish_scan (s);
539141cc406Sopenharmony_ci  free (mp->cb.buf);
540141cc406Sopenharmony_ci  free (mp->buf);
541141cc406Sopenharmony_ci  free (mp);
542141cc406Sopenharmony_ci  s->subdriver = NULL;
543141cc406Sopenharmony_ci}
544141cc406Sopenharmony_ci
545141cc406Sopenharmony_cistatic unsigned
546141cc406Sopenharmony_cicalc_raw_width (pixma_t * s, const pixma_scan_param_t * sp)
547141cc406Sopenharmony_ci{
548141cc406Sopenharmony_ci  unsigned raw_width;
549141cc406Sopenharmony_ci  /* FIXME: Does MP730 need the alignment? */
550141cc406Sopenharmony_ci  /*  TODO test: MP710/740 */
551141cc406Sopenharmony_ci  if (sp->channels == 1)
552141cc406Sopenharmony_ci    {
553141cc406Sopenharmony_ci      if (sp->depth == 8)   /* grayscale  */
554141cc406Sopenharmony_ci        {
555141cc406Sopenharmony_ci          if (s->cfg->pid == MP5_PID   ||
556141cc406Sopenharmony_ci              s->cfg->pid == MP10_PID  ||
557141cc406Sopenharmony_ci              s->cfg->pid == MP700_PID ||
558141cc406Sopenharmony_ci              s->cfg->pid == MP730_PID ||
559141cc406Sopenharmony_ci              s->cfg->pid == MP360_PID ||
560141cc406Sopenharmony_ci              s->cfg->pid == MP370_PID ||
561141cc406Sopenharmony_ci              s->cfg->pid == MP375R_PID ||
562141cc406Sopenharmony_ci              s->cfg->pid == MP390_PID ||
563141cc406Sopenharmony_ci	      s->cfg->pid == IR1020_PID)
564141cc406Sopenharmony_ci            raw_width = ALIGN_SUP (sp->w, 4);
565141cc406Sopenharmony_ci          else
566141cc406Sopenharmony_ci            raw_width = ALIGN_SUP (sp->w, 12);
567141cc406Sopenharmony_ci        }
568141cc406Sopenharmony_ci      else   /* depth = 1 : LINEART */
569141cc406Sopenharmony_ci        raw_width = ALIGN_SUP (sp->w, 16);
570141cc406Sopenharmony_ci    }
571141cc406Sopenharmony_ci  else
572141cc406Sopenharmony_ci    raw_width = ALIGN_SUP (sp->w, 4);
573141cc406Sopenharmony_ci  return raw_width;
574141cc406Sopenharmony_ci}
575141cc406Sopenharmony_ci
576141cc406Sopenharmony_cistatic int
577141cc406Sopenharmony_cimp730_check_param (pixma_t * s, pixma_scan_param_t * sp)
578141cc406Sopenharmony_ci{
579141cc406Sopenharmony_ci  uint8_t k = 1;
580141cc406Sopenharmony_ci
581141cc406Sopenharmony_ci  /* check if channels is 3, or if depth is 1 then channels also 1 else set depth to 8 */
582141cc406Sopenharmony_ci  if ((sp->channels==3) || !(sp->channels==1 && sp->depth==1))
583141cc406Sopenharmony_ci    {
584141cc406Sopenharmony_ci      sp->depth=8;
585141cc406Sopenharmony_ci    }
586141cc406Sopenharmony_ci  /* for MP5, MP10, MP360/370, MP700/730 in grayscale & lineart modes, max scan res is 600 dpi */
587141cc406Sopenharmony_ci  if (s->cfg->pid == MP5_PID   ||
588141cc406Sopenharmony_ci      s->cfg->pid == MP10_PID  ||
589141cc406Sopenharmony_ci      s->cfg->pid == MP700_PID ||
590141cc406Sopenharmony_ci      s->cfg->pid == MP730_PID ||
591141cc406Sopenharmony_ci      s->cfg->pid == MP360_PID ||
592141cc406Sopenharmony_ci      s->cfg->pid == MP370_PID ||
593141cc406Sopenharmony_ci      s->cfg->pid == MP375R_PID ||
594141cc406Sopenharmony_ci      s->cfg->pid == MP390_PID)
595141cc406Sopenharmony_ci    {
596141cc406Sopenharmony_ci      if (sp->channels == 1)
597141cc406Sopenharmony_ci          k = sp->xdpi / MIN (sp->xdpi, 600);
598141cc406Sopenharmony_ci    }
599141cc406Sopenharmony_ci
600141cc406Sopenharmony_ci  sp->x /= k;
601141cc406Sopenharmony_ci  sp->y /= k;
602141cc406Sopenharmony_ci  sp->h /= k;
603141cc406Sopenharmony_ci  sp->xdpi /= k;
604141cc406Sopenharmony_ci  sp->ydpi = sp->xdpi;
605141cc406Sopenharmony_ci
606141cc406Sopenharmony_ci  sp->w = calc_raw_width (s, sp);
607141cc406Sopenharmony_ci  sp->w /= k;
608141cc406Sopenharmony_ci  sp->line_size = (calc_raw_width (s, sp) * sp->channels * sp->depth) / 8;
609141cc406Sopenharmony_ci
610141cc406Sopenharmony_ci  return 0;
611141cc406Sopenharmony_ci}
612141cc406Sopenharmony_ci
613141cc406Sopenharmony_cistatic int
614141cc406Sopenharmony_cimp730_scan (pixma_t * s)
615141cc406Sopenharmony_ci{
616141cc406Sopenharmony_ci  int error, n;
617141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
618141cc406Sopenharmony_ci  uint8_t *buf;
619141cc406Sopenharmony_ci
620141cc406Sopenharmony_ci  if (mp->state != state_idle)
621141cc406Sopenharmony_ci    return PIXMA_EBUSY;
622141cc406Sopenharmony_ci
623141cc406Sopenharmony_ci  /* clear interrupt packets buffer */
624141cc406Sopenharmony_ci  while (handle_interrupt (s, 0) > 0)
625141cc406Sopenharmony_ci    {
626141cc406Sopenharmony_ci    }
627141cc406Sopenharmony_ci
628141cc406Sopenharmony_ci  mp->raw_width = calc_raw_width (s, s->param);
629141cc406Sopenharmony_ci  PDBG (pixma_dbg (3, "raw_width = %u\n", mp->raw_width));
630141cc406Sopenharmony_ci
631141cc406Sopenharmony_ci  n = IMAGE_BLOCK_SIZE / s->param->line_size + 1;
632141cc406Sopenharmony_ci  buf = (uint8_t *) malloc ((n + 1) * s->param->line_size + IMAGE_BLOCK_SIZE);
633141cc406Sopenharmony_ci  if (!buf)
634141cc406Sopenharmony_ci    return PIXMA_ENOMEM;
635141cc406Sopenharmony_ci  mp->buf = buf;
636141cc406Sopenharmony_ci  mp->lbuf = buf;
637141cc406Sopenharmony_ci  mp->imgbuf = buf + n * s->param->line_size;
638141cc406Sopenharmony_ci  mp->imgbuf_len = 0;
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci  error = step1 (s);
641141cc406Sopenharmony_ci  if (error >= 0)
642141cc406Sopenharmony_ci    error = start_session (s);
643141cc406Sopenharmony_ci  if (error >= 0)
644141cc406Sopenharmony_ci    mp->state = state_scanning;
645141cc406Sopenharmony_ci  if (error >= 0)
646141cc406Sopenharmony_ci    error = select_source (s);
647141cc406Sopenharmony_ci  if (error >= 0)
648141cc406Sopenharmony_ci    error = send_scan_param (s);
649141cc406Sopenharmony_ci  if (error < 0)
650141cc406Sopenharmony_ci    {
651141cc406Sopenharmony_ci      mp730_finish_scan (s);
652141cc406Sopenharmony_ci      return error;
653141cc406Sopenharmony_ci    }
654141cc406Sopenharmony_ci  mp->last_block = 0;
655141cc406Sopenharmony_ci  return 0;
656141cc406Sopenharmony_ci}
657141cc406Sopenharmony_ci
658141cc406Sopenharmony_cistatic int
659141cc406Sopenharmony_cimp730_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib)
660141cc406Sopenharmony_ci{
661141cc406Sopenharmony_ci  int error, n;
662141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
663141cc406Sopenharmony_ci  unsigned block_size, bytes_received;
664141cc406Sopenharmony_ci  uint8_t header[16];
665141cc406Sopenharmony_ci
666141cc406Sopenharmony_ci  do
667141cc406Sopenharmony_ci    {
668141cc406Sopenharmony_ci      do
669141cc406Sopenharmony_ci	{
670141cc406Sopenharmony_ci	  if (s->cancel)
671141cc406Sopenharmony_ci	    return PIXMA_ECANCELED;
672141cc406Sopenharmony_ci	  if (mp->last_block)           /* end of image */
673141cc406Sopenharmony_ci	      return 0;
674141cc406Sopenharmony_ci
675141cc406Sopenharmony_ci	  error = read_image_block (s, header, mp->imgbuf + mp->imgbuf_len);
676141cc406Sopenharmony_ci	  if (error < 0)
677141cc406Sopenharmony_ci	    return error;
678141cc406Sopenharmony_ci
679141cc406Sopenharmony_ci	  bytes_received = error;
680141cc406Sopenharmony_ci	  block_size = pixma_get_be16 (header + 4);
681141cc406Sopenharmony_ci	  mp->last_block = ((header[2] & 0x28) == 0x28);
682141cc406Sopenharmony_ci	  if (mp->last_block)
683141cc406Sopenharmony_ci	    {    /* end of image */
684141cc406Sopenharmony_ci	      mp->state = state_finished;
685141cc406Sopenharmony_ci	    }
686141cc406Sopenharmony_ci	  if ((header[2] & ~0x38) != 0)
687141cc406Sopenharmony_ci	    {
688141cc406Sopenharmony_ci	      PDBG (pixma_dbg (1, "WARNING: Unexpected result header\n"));
689141cc406Sopenharmony_ci	      PDBG (pixma_hexdump (1, header, 16));
690141cc406Sopenharmony_ci	    }
691141cc406Sopenharmony_ci	  PASSERT (bytes_received == block_size);
692141cc406Sopenharmony_ci
693141cc406Sopenharmony_ci	  if (block_size == 0)
694141cc406Sopenharmony_ci	    {
695141cc406Sopenharmony_ci	      /* no image data at this moment. */
696141cc406Sopenharmony_ci	      /*pixma_sleep(100000); *//* FIXME: too short, too long? */
697141cc406Sopenharmony_ci	      handle_interrupt (s, 100);
698141cc406Sopenharmony_ci            }
699141cc406Sopenharmony_ci	}
700141cc406Sopenharmony_ci      while (block_size == 0);
701141cc406Sopenharmony_ci
702141cc406Sopenharmony_ci      /* TODO: simplify! */
703141cc406Sopenharmony_ci      mp->imgbuf_len += bytes_received;
704141cc406Sopenharmony_ci      n = mp->imgbuf_len / s->param->line_size;
705141cc406Sopenharmony_ci      /* n = number of full lines (rows) we have in the buffer. */
706141cc406Sopenharmony_ci      if (n != 0)
707141cc406Sopenharmony_ci	{
708141cc406Sopenharmony_ci	  if (s->param->channels != 1    &&
709141cc406Sopenharmony_ci	      s->cfg->pid != MF5630_PID  &&
710141cc406Sopenharmony_ci	      s->cfg->pid != MF5650_PID  &&
711141cc406Sopenharmony_ci	      s->cfg->pid != MF5730_PID  &&
712141cc406Sopenharmony_ci	      s->cfg->pid != MF5750_PID  &&
713141cc406Sopenharmony_ci	      s->cfg->pid != MF5770_PID  &&
714141cc406Sopenharmony_ci	      s->cfg->pid != MF3110_PID  &&
715141cc406Sopenharmony_ci	      s->cfg->pid != IR1020_PID)
716141cc406Sopenharmony_ci	    {
717141cc406Sopenharmony_ci	      /* color, and not an MF57x0 nor MF3110 */
718141cc406Sopenharmony_ci	      pack_rgb (mp->imgbuf, n, mp->raw_width, mp->lbuf);
719141cc406Sopenharmony_ci	    }
720141cc406Sopenharmony_ci	  else
721141cc406Sopenharmony_ci             /* grayscale/lineart or MF57x0 or MF3110 */
722141cc406Sopenharmony_ci             memcpy (mp->lbuf, mp->imgbuf, n * s->param->line_size);
723141cc406Sopenharmony_ci
724141cc406Sopenharmony_ci	  block_size = n * s->param->line_size;
725141cc406Sopenharmony_ci	  mp->imgbuf_len -= block_size;
726141cc406Sopenharmony_ci	  memcpy (mp->imgbuf, mp->imgbuf + block_size, mp->imgbuf_len);
727141cc406Sopenharmony_ci	}
728141cc406Sopenharmony_ci    }
729141cc406Sopenharmony_ci  while (n == 0);
730141cc406Sopenharmony_ci
731141cc406Sopenharmony_ci  ib->rptr = mp->lbuf;
732141cc406Sopenharmony_ci  ib->rend = mp->lbuf + block_size;
733141cc406Sopenharmony_ci  return ib->rend - ib->rptr;
734141cc406Sopenharmony_ci}
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_cistatic void
737141cc406Sopenharmony_cimp730_finish_scan (pixma_t * s)
738141cc406Sopenharmony_ci{
739141cc406Sopenharmony_ci  int error, aborted = 0;
740141cc406Sopenharmony_ci  mp730_t *mp = (mp730_t *) s->subdriver;
741141cc406Sopenharmony_ci
742141cc406Sopenharmony_ci  switch (mp->state)
743141cc406Sopenharmony_ci    {
744141cc406Sopenharmony_ci    case state_transfering:
745141cc406Sopenharmony_ci      drain_bulk_in (s);
746141cc406Sopenharmony_ci      /* fall through */
747141cc406Sopenharmony_ci    case state_scanning:
748141cc406Sopenharmony_ci    case state_warmup:
749141cc406Sopenharmony_ci      aborted = 1;
750141cc406Sopenharmony_ci      error = abort_session (s);
751141cc406Sopenharmony_ci      if (error < 0)
752141cc406Sopenharmony_ci	PDBG (pixma_dbg
753141cc406Sopenharmony_ci	      (1, "WARNING:abort_session() failed %s\n",
754141cc406Sopenharmony_ci	       pixma_strerror (error)));
755141cc406Sopenharmony_ci      /* fall through */
756141cc406Sopenharmony_ci    case state_finished:
757141cc406Sopenharmony_ci      query_status (s);
758141cc406Sopenharmony_ci      query_status (s);
759141cc406Sopenharmony_ci      activate (s, 0);
760141cc406Sopenharmony_ci
761141cc406Sopenharmony_ci      // MF57x0 devices don't require abort_session() after the last page
762141cc406Sopenharmony_ci      if (!aborted &&
763141cc406Sopenharmony_ci          (s->param->source == PIXMA_SOURCE_ADF ||
764141cc406Sopenharmony_ci           s->param->source == PIXMA_SOURCE_ADFDUP) &&
765141cc406Sopenharmony_ci           has_paper (s) &&
766141cc406Sopenharmony_ci           (s->cfg->pid == MF5630_PID ||
767141cc406Sopenharmony_ci            s->cfg->pid == MF5650_PID ||
768141cc406Sopenharmony_ci            s->cfg->pid == MF5730_PID ||
769141cc406Sopenharmony_ci            s->cfg->pid == MF5750_PID ||
770141cc406Sopenharmony_ci            s->cfg->pid == MF5770_PID ||
771141cc406Sopenharmony_ci            s->cfg->pid == IR1020_PID))
772141cc406Sopenharmony_ci      {
773141cc406Sopenharmony_ci        error = abort_session (s);
774141cc406Sopenharmony_ci        if (error < 0)
775141cc406Sopenharmony_ci          PDBG (pixma_dbg
776141cc406Sopenharmony_ci                (1, "WARNING:abort_session() failed %s\n",
777141cc406Sopenharmony_ci                 pixma_strerror (error)));
778141cc406Sopenharmony_ci      }
779141cc406Sopenharmony_ci
780141cc406Sopenharmony_ci      mp->buf = mp->lbuf = mp->imgbuf = NULL;
781141cc406Sopenharmony_ci      mp->state = state_idle;
782141cc406Sopenharmony_ci      /* fall through */
783141cc406Sopenharmony_ci    case state_idle:
784141cc406Sopenharmony_ci      break;
785141cc406Sopenharmony_ci    }
786141cc406Sopenharmony_ci}
787141cc406Sopenharmony_ci
788141cc406Sopenharmony_cistatic void
789141cc406Sopenharmony_cimp730_wait_event (pixma_t * s, int timeout)
790141cc406Sopenharmony_ci{
791141cc406Sopenharmony_ci  /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for
792141cc406Sopenharmony_ci   * instance. */
793141cc406Sopenharmony_ci  while (s->events == 0 && handle_interrupt (s, timeout) > 0)
794141cc406Sopenharmony_ci    {
795141cc406Sopenharmony_ci    }
796141cc406Sopenharmony_ci}
797141cc406Sopenharmony_ci
798141cc406Sopenharmony_cistatic int
799141cc406Sopenharmony_cimp730_get_status (pixma_t * s, pixma_device_status_t * status)
800141cc406Sopenharmony_ci{
801141cc406Sopenharmony_ci  int error;
802141cc406Sopenharmony_ci
803141cc406Sopenharmony_ci  error = query_status (s);
804141cc406Sopenharmony_ci  if (error < 0)
805141cc406Sopenharmony_ci    return error;
806141cc406Sopenharmony_ci  status->hardware = PIXMA_HARDWARE_OK;
807141cc406Sopenharmony_ci  status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER;
808141cc406Sopenharmony_ci  return 0;
809141cc406Sopenharmony_ci}
810141cc406Sopenharmony_ci
811141cc406Sopenharmony_ci
812141cc406Sopenharmony_cistatic const pixma_scan_ops_t pixma_mp730_ops = {
813141cc406Sopenharmony_ci  mp730_open,
814141cc406Sopenharmony_ci  mp730_close,
815141cc406Sopenharmony_ci  mp730_scan,
816141cc406Sopenharmony_ci  mp730_fill_buffer,
817141cc406Sopenharmony_ci  mp730_finish_scan,
818141cc406Sopenharmony_ci  mp730_wait_event,
819141cc406Sopenharmony_ci  mp730_check_param,
820141cc406Sopenharmony_ci  mp730_get_status
821141cc406Sopenharmony_ci};
822141cc406Sopenharmony_ci
823141cc406Sopenharmony_ci/* TODO: implement adftpu_min_dpi & adftpu_max_dpi for grayscale & lineart */
824141cc406Sopenharmony_ci#define DEVICE(name, model, pid, dpi, w, h, cap) {           \
825141cc406Sopenharmony_ci              name,              /* name */           \
826141cc406Sopenharmony_ci              model,             /* model */		      \
827141cc406Sopenharmony_ci              0x04a9, pid,       /* vid pid */	      \
828141cc406Sopenharmony_ci              1,                 /* iface */		      \
829141cc406Sopenharmony_ci              &pixma_mp730_ops,  /* ops */            \
830141cc406Sopenharmony_ci              0, 0,              /* min_xdpi & min_xdpi_16 not used in this subdriver */ \
831141cc406Sopenharmony_ci              dpi, dpi,          /* xdpi, ydpi */	    \
832141cc406Sopenharmony_ci              0, 0,              /* adftpu_min_dpi & adftpu_max_dpi not used in this subdriver */ \
833141cc406Sopenharmony_ci              0, 0,              /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */  \
834141cc406Sopenharmony_ci              w, h,              /* width, height */	\
835141cc406Sopenharmony_ci        PIXMA_CAP_GRAY|PIXMA_CAP_EVENTS|cap           \
836141cc406Sopenharmony_ci}
837141cc406Sopenharmony_ciconst pixma_config_t pixma_mp730_devices[] = {
838141cc406Sopenharmony_ci/* TODO: check area limits */
839141cc406Sopenharmony_ci  DEVICE ("PIXUS MP5/SmartBase MPC190/imageCLASS MPC190","MP5", MP5_PID, 600, 636, 868, PIXMA_CAP_LINEART),/* color scan can do 600x1200 */
840141cc406Sopenharmony_ci  DEVICE ("PIXUS MP10/SmartBase MPC200/imageCLASS MPC200","MP10", MP10_PID, 600, 636, 868, PIXMA_CAP_LINEART),/* color scan can do 600x1200 */
841141cc406Sopenharmony_ci  DEVICE ("PIXMA MP360", "MP360", MP360_PID, 1200, 636, 868, PIXMA_CAP_LINEART),
842141cc406Sopenharmony_ci  DEVICE ("PIXMA MP370", "MP370", MP370_PID, 1200, 636, 868, PIXMA_CAP_LINEART),
843141cc406Sopenharmony_ci  DEVICE ("PIXMA MP375R", "MP375R", MP375R_PID, 1200, 636, 868, PIXMA_CAP_LINEART),
844141cc406Sopenharmony_ci  DEVICE ("PIXMA MP390", "MP390", MP390_PID, 1200, 636, 868, PIXMA_CAP_LINEART),
845141cc406Sopenharmony_ci  DEVICE ("PIXMA MP700", "MP700", MP700_PID, 1200, 638, 877 /*1035 */ , PIXMA_CAP_LINEART),
846141cc406Sopenharmony_ci  DEVICE ("PIXMA MP710", "MP710", MP710_PID, 1200, 637, 868, PIXMA_CAP_LINEART),
847141cc406Sopenharmony_ci  DEVICE ("PIXMA MP730", "MP730", MP730_PID, 1200, 637, 868, PIXMA_CAP_ADF | PIXMA_CAP_LINEART),
848141cc406Sopenharmony_ci  DEVICE ("PIXMA MP740", "MP740", MP740_PID, 1200, 637, 868, PIXMA_CAP_ADF | PIXMA_CAP_LINEART),
849141cc406Sopenharmony_ci
850141cc406Sopenharmony_ci  DEVICE ("Canon imageCLASS MF5630", "MF5630", MF5630_PID, 1200, 636, 868, PIXMA_CAP_ADF),
851141cc406Sopenharmony_ci  DEVICE ("Canon laserBase MF5650", "MF5650", MF5650_PID, 1200, 636, 868, PIXMA_CAP_ADF),
852141cc406Sopenharmony_ci  DEVICE ("Canon imageCLASS MF5730", "MF5730", MF5730_PID, 1200, 636, 868, PIXMA_CAP_ADF),
853141cc406Sopenharmony_ci  DEVICE ("Canon imageCLASS MF5750", "MF5750", MF5750_PID, 1200, 636, 868, PIXMA_CAP_ADF),
854141cc406Sopenharmony_ci  DEVICE ("Canon imageCLASS MF5770", "MF5770", MF5770_PID, 1200, 636, 868, PIXMA_CAP_ADF),
855141cc406Sopenharmony_ci  DEVICE ("Canon imageCLASS MF3110", "MF3110", MF3110_PID, 600, 636, 868, 0),
856141cc406Sopenharmony_ci
857141cc406Sopenharmony_ci  DEVICE ("Canon iR 1020/1024/1025", "iR1020", IR1020_PID, 600, 636, 868, PIXMA_CAP_ADFDUP),
858141cc406Sopenharmony_ci
859141cc406Sopenharmony_ci  DEVICE (NULL, NULL, 0, 0, 0, 0, 0)
860141cc406Sopenharmony_ci};
861