1/* sane - Scanner Access Now Easy.
2   Copyright (C) 2001-2012 Stéphane Voltz <stef.dev@free.fr>
3   This file is part of the SANE package.
4
5   This program is free software; you can redistribute it and/or
6   modify it under the terms of the GNU General Public License as
7   published by the Free Software Foundation; either version 2 of the
8   License, or (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
18   As a special exception, the authors of SANE give permission for
19   additional uses of the libraries contained in this release of SANE.
20
21   The exception is that, if you link a SANE library with other files
22   to produce an executable, this does not by itself cause the
23   resulting executable to be covered by the GNU General Public
24   License.  Your use of that executable is in no way restricted on
25   account of linking the SANE library code into it.
26
27   This exception does not, however, invalidate any other reasons why
28   the executable file might be covered by the GNU General Public
29   License.
30
31   If you submit changes to SANE to the maintainers to be included in
32   a subsequent release, you agree by submitting the changes that
33   those changes may be distributed with this exception intact.
34
35   If you write modifications of your own for SANE, it is your choice
36   whether to permit this exception to apply to your modifications.
37   If you do not wish that, delete this exception notice.
38
39   This file implements a SANE backend for Umax PP flatbed scanners.  */
40
41#define DEBUG_DECLARE_ONLY
42#undef BACKEND_NAME
43#define BACKEND_NAME umax_pp
44
45#include "../include/sane/config.h"
46#include <stdlib.h>
47#include <string.h>
48#ifdef HAVE_UNISTD_H
49#include <unistd.h>
50#endif
51#include <stdio.h>
52#include "../include/sane/sanei_debug.h"
53
54#define __MAIN__
55
56
57#include "umax_pp_mid.h"
58
59/* this function locks the parallel port so that other devices */
60/* won't interfere. Returns UMAX1220P_BUSY is port cannot be   */
61/* lock or UMAX1220P_OK if it is locked                        */
62static int locked = 0;
63#ifdef HAVE_LINUX_PPDEV_H
64static int exmode = IEEE1284_MODE_COMPAT;
65static int exflags = 0;
66#endif
67
68static int
69lock_parport (void)
70{
71#ifdef HAVE_LINUX_PPDEV_H
72  int mode, fd;
73#endif
74
75  DBG_INIT ();
76  DBG (3, "lock_parport\n");
77
78#ifdef HAVE_LINUX_PPDEV_H
79  fd = sanei_umax_pp_getparport ();
80  if ((fd > 0) && (!locked))
81    {
82      if (ioctl (sanei_umax_pp_getparport (), PPCLAIM))
83        {
84          return UMAX1220P_BUSY;
85        }
86#ifdef PPGETMODE
87      if (ioctl (fd, PPGETMODE, &exmode))
88        exmode = IEEE1284_MODE_COMPAT;
89      if (ioctl (fd, PPGETFLAGS, &exflags))
90        exflags = 0;
91#endif
92      mode = IEEE1284_MODE_EPP;
93      ioctl (fd, PPNEGOT, &mode);
94      ioctl (fd, PPSETMODE, &mode);
95      locked = 1;
96    }
97#else
98  locked = 1;
99#endif
100  return UMAX1220P_OK;
101}
102
103
104/* this function release parport */
105static int
106unlock_parport (void)
107{
108#ifdef HAVE_LINUX_PPDEV_H
109  int fd, mode;
110
111  fd = sanei_umax_pp_getparport ();
112  if ((fd > 0) && (locked))
113    {
114      mode = IEEE1284_MODE_COMPAT;
115      ioctl (fd, PPNEGOT, &mode);
116      ioctl (fd, PPSETMODE, &exmode);
117#ifdef PPSETFLAGS
118      ioctl (fd, PPSETFLAGS, &exflags);
119#endif
120      ioctl (fd, PPRELEASE);
121      locked = 1;
122    }
123#endif
124  DBG (3, "unlock_parport\n");
125  locked = 0;
126  return UMAX1220P_OK;
127}
128
129
130
131
132/*
133 *
134 *  This function recognize the scanner model by sending an image
135 * filter command. 1220P will use it as is, but 2000P will return
136 * it back modified.
137 *
138 */
139int
140sanei_umax_pp_model (int port, int *model)
141{
142  int recover = 0, rc;
143
144  /* set up port */
145  DBG (3, "sanei_umax_pp_model\n");
146  sanei_umax_pp_setport (port);
147  if (lock_parport () == UMAX1220P_BUSY)
148    return UMAX1220P_BUSY;
149
150  /* init transport layer */
151  /* 0: failed
152     1: success
153     2: retry
154     3: busy
155   */
156  do
157    {
158      rc = sanei_umax_pp_initTransport (recover);
159    }
160  while (rc == 2);
161
162  if (rc == 3)
163    {
164      unlock_parport ();
165      return UMAX1220P_BUSY;
166    }
167  if (rc != 1)
168    {
169      DBG (0, "sanei_umax_pp_initTransport() failed (%s:%d)\n", __FILE__,
170           __LINE__);
171      unlock_parport ();
172      return UMAX1220P_TRANSPORT_FAILED;
173    }
174
175  /* check model only, and if only none given in conf file */
176  if (!sanei_umax_pp_getastra ())
177    {
178      rc = sanei_umax_pp_checkModel ();
179    }
180  else
181    {
182      rc = sanei_umax_pp_getastra ();
183    }
184  sanei_umax_pp_endSession ();
185  unlock_parport ();
186  if (rc < 600)
187    {
188      DBG (0, "sanei_umax_pp_CheckModel() failed (%s:%d)\n", __FILE__,
189           __LINE__);
190      return UMAX1220P_PROBE_FAILED;
191    }
192  *model = rc;
193
194
195  /* OK */
196  return UMAX1220P_OK;
197}
198
199int
200sanei_umax_pp_attach (int port, const char *name)
201{
202  int recover = 0;
203
204  /* set up port */
205  if (name == NULL)
206    {
207      DBG (3, "sanei_umax_pp_attach(%d,NULL)\n", port);
208    }
209  else
210    {
211      DBG (3, "sanei_umax_pp_attach(%d,%s)\n", port, name);
212    }
213
214  sanei_umax_pp_setport (port);
215  if (sanei_umax_pp_initPort (port, name) != 1)
216    return UMAX1220P_PROBE_FAILED;
217
218  /* init port locks the port, so we flag that */
219  locked = 1;
220
221  if (sanei_umax_pp_probeScanner (recover) != 1)
222    {
223      if (recover)
224        {
225          sanei_umax_pp_initTransport (recover);
226          sanei_umax_pp_endSession ();
227          if (sanei_umax_pp_probeScanner (recover) != 1)
228            {
229              DBG (0, "Recover failed ....\n");
230              unlock_parport ();
231              return UMAX1220P_PROBE_FAILED;
232            }
233        }
234      else
235        {
236          unlock_parport ();
237          return UMAX1220P_PROBE_FAILED;
238        }
239    }
240  sanei_umax_pp_endSession ();
241  unlock_parport ();
242
243
244  /* OK */
245  return UMAX1220P_OK;
246}
247
248
249int
250sanei_umax_pp_open (int port, char *name)
251{
252  int rc;
253  int recover = 0;
254
255  /* set up port */
256  DBG (3, "sanei_umax_pp_open\n");
257
258  if (name == NULL)
259    sanei_umax_pp_setport (port);
260
261  if (lock_parport () == UMAX1220P_BUSY)
262    return UMAX1220P_BUSY;
263
264  /* init transport layer */
265  /* 0: failed
266     1: success
267     2: retry
268     3: scanner busy
269   */
270  do
271    {
272      rc = sanei_umax_pp_initTransport (recover);
273    }
274  while (rc == 2);
275
276  if (rc == 3)
277    {
278      unlock_parport ();
279      return UMAX1220P_BUSY;
280    }
281
282  if (rc != 1)
283    {
284
285      DBG (0, "sanei_umax_pp_initTransport() failed (%s:%d)\n", __FILE__,
286           __LINE__);
287      unlock_parport ();
288      return UMAX1220P_TRANSPORT_FAILED;
289    }
290  /* init scanner */
291  if (sanei_umax_pp_initScanner (recover) == 0)
292    {
293      DBG (0, "sanei_umax_pp_initScanner() failed (%s:%d)\n", __FILE__,
294           __LINE__);
295      sanei_umax_pp_endSession ();
296      unlock_parport ();
297      return UMAX1220P_SCANNER_FAILED;
298    }
299
300  /* OK */
301  unlock_parport ();
302  return UMAX1220P_OK;
303}
304
305
306int
307sanei_umax_pp_cancel (void)
308{
309  DBG (3, "sanei_umax_pp_cancel\n");
310  if (lock_parport () == UMAX1220P_BUSY)
311    return UMAX1220P_BUSY;
312
313  /* maybe EPAT reset here if exists */
314  sanei_umax_pp_cmdSync (0xC2);
315  sanei_umax_pp_cmdSync (0x00);
316  sanei_umax_pp_cmdSync (0x00);
317  if (sanei_umax_pp_park () == 0)
318    {
319      DBG (0, "sanei_umax_pp_park failed !!! (%s:%d)\n", __FILE__, __LINE__);
320      unlock_parport ();
321      return UMAX1220P_PARK_FAILED;
322    }
323  /* endSession() cancels any pending command  */
324  /* such as parking ...., so we only return   */
325  unlock_parport ();
326  return UMAX1220P_OK;
327}
328
329
330
331int
332sanei_umax_pp_start (int x, int y, int width, int height, int dpi, int color,
333                     int autoset,
334                     int gain, int offset, int *rbpp, int *rtw,
335                     int *rth)
336{
337  int col = BW_MODE;
338
339  DBG (3, "sanei_umax_pp_start\n");
340  if (lock_parport () == UMAX1220P_BUSY)
341    return UMAX1220P_BUSY;
342  /* end session isn't done by cancel any more */
343  sanei_umax_pp_endSession ();
344
345  if (autoset)
346    sanei_umax_pp_setauto (1);
347  else
348    sanei_umax_pp_setauto (0);
349
350  switch (color)
351    {
352    case 0:
353      col = BW2_MODE;
354      break;
355    case 1:
356      col = BW_MODE;
357      break;
358    case 2:
359      col = RGB_MODE;
360      break;
361    }
362
363  if (sanei_umax_pp_startScan
364      (x + sanei_umax_pp_getLeft (), y, width, height, dpi, col, gain,
365       offset, rbpp, rtw, rth) != 1)
366    {
367      sanei_umax_pp_endSession ();
368      unlock_parport ();
369      return UMAX1220P_START_FAILED;
370    }
371  unlock_parport ();
372  return UMAX1220P_OK;
373}
374
375int
376sanei_umax_pp_read (long len, int window, int dpi, int last,
377                    unsigned char *buffer)
378{
379  int read = 0;
380  int bytes;
381
382  DBG (3, "sanei_umax_pp_read\n");
383  if (lock_parport () == UMAX1220P_BUSY)
384    return UMAX1220P_BUSY;
385
386  /* since 610P may override len and last to meet its */
387  /* hardware requirements, we have to loop until we  */
388  /* have all the data                                */
389  while (read < len)
390    {
391      bytes =
392        sanei_umax_pp_readBlock (len - read, window, dpi, last,
393                                 buffer + read);
394      if (bytes == 0)
395        {
396          sanei_umax_pp_endSession ();
397          return UMAX1220P_READ_FAILED;
398        }
399      read += bytes;
400    }
401  unlock_parport ();
402  return UMAX1220P_OK;
403}
404
405
406
407int
408sanei_umax_pp_lamp (int on)
409{
410  /* init transport layer */
411  DBG (3, "sanei_umax_pp_lamp\n");
412
413  /* no lamp support for 610P ... */
414  if (sanei_umax_pp_getastra () < 1210)
415    return UMAX1220P_OK;
416
417  if (lock_parport () == UMAX1220P_BUSY)
418    return UMAX1220P_BUSY;
419
420  if (sanei_umax_pp_setLamp (on) == 0)
421    {
422      DBG (0, "Setting lamp state failed!\n");
423    }
424
425  unlock_parport ();
426  return UMAX1220P_OK;
427}
428
429
430
431
432int
433sanei_umax_pp_status (void)
434{
435  int status;
436
437  DBG (3, "sanei_umax_pp_status\n");
438  if (lock_parport () == UMAX1220P_BUSY)
439    return UMAX1220P_BUSY;
440  /* check if head is at home */
441  sanei_umax_pp_cmdSync (0x40);
442  status = sanei_umax_pp_scannerStatus ();
443  unlock_parport ();
444  DBG (8, "sanei_umax_pp_status=0x%02X\n", status);
445  if (((status & ASIC_BIT) != 0x00)||((status & MOTOR_BIT) == 0x00))
446    return UMAX1220P_BUSY;
447
448  return UMAX1220P_OK;
449}
450
451int
452sanei_umax_pp_close ()
453{
454#ifdef HAVE_LINUX_PPDEV_H
455  int fd;
456#endif
457
458  DBG (3, "sanei_umax_pp_close\n");
459
460  lock_parport ();
461  sanei_umax_pp_endSession ();
462  unlock_parport ();
463
464#ifdef HAVE_LINUX_PPDEV_H
465  fd = sanei_umax_pp_getparport ();
466  if (fd > 0)
467    {
468      close (fd);
469      sanei_umax_pp_setparport (0);
470    }
471#endif
472  return UMAX1220P_OK;
473}
474