kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			476 wiersze
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			476 wiersze
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
| /* sane - Scanner Access Now Easy.
 | |
|    Copyright (C) 2001-2012 Stéphane Voltz <stef.dev@free.fr>
 | |
|    This file is part of the SANE package.
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or
 | |
|    modify it under the terms of the GNU General Public License as
 | |
|    published by the Free Software Foundation; either version 2 of the
 | |
|    License, or (at your option) any later version.
 | |
| 
 | |
|    This program is distributed in the hope that it will be useful, but
 | |
|    WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|    General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU General Public License
 | |
|    along with this program; if not, write to the Free Software
 | |
|    Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 | |
|    MA 02111-1307, USA.
 | |
| 
 | |
|    As a special exception, the authors of SANE give permission for
 | |
|    additional uses of the libraries contained in this release of SANE.
 | |
| 
 | |
|    The exception is that, if you link a SANE library with other files
 | |
|    to produce an executable, this does not by itself cause the
 | |
|    resulting executable to be covered by the GNU General Public
 | |
|    License.  Your use of that executable is in no way restricted on
 | |
|    account of linking the SANE library code into it.
 | |
| 
 | |
|    This exception does not, however, invalidate any other reasons why
 | |
|    the executable file might be covered by the GNU General Public
 | |
|    License.
 | |
| 
 | |
|    If you submit changes to SANE to the maintainers to be included in
 | |
|    a subsequent release, you agree by submitting the changes that
 | |
|    those changes may be distributed with this exception intact.
 | |
| 
 | |
|    If you write modifications of your own for SANE, it is your choice
 | |
|    whether to permit this exception to apply to your modifications.
 | |
|    If you do not wish that, delete this exception notice.
 | |
| 
 | |
|    This file implements a SANE backend for Umax PP flatbed scanners.  */
 | |
| 
 | |
| #define DEBUG_DECLARE_ONLY
 | |
| #undef BACKEND_NAME
 | |
| #define BACKEND_NAME umax_pp
 | |
| 
 | |
| #include "../include/sane/config.h"
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #ifdef HAVE_UNISTD_H
 | |
| #include <unistd.h>
 | |
| #endif
 | |
| #include <stdio.h>
 | |
| #include "../include/sane/sanei_debug.h"
 | |
| 
 | |
| #define __MAIN__
 | |
| 
 | |
| 
 | |
| #include "umax_pp_mid.h"
 | |
| 
 | |
| /* this function locks the parallel port so that other devices */
 | |
| /* won't interfere. Returns UMAX1220P_BUSY is port cannot be   */
 | |
| /* lock or UMAX1220P_OK if it is locked                        */
 | |
| static int locked = 0;
 | |
| #ifdef HAVE_LINUX_PPDEV_H
 | |
| static int exmode = IEEE1284_MODE_COMPAT;
 | |
| static int exflags = 0;
 | |
| #endif
 | |
| 
 | |
| static int
 | |
| lock_parport (void)
 | |
| {
 | |
| #ifdef HAVE_LINUX_PPDEV_H
 | |
|   int mode, fd;
 | |
| #endif
 | |
| 
 | |
|   DBG_INIT ();
 | |
|   DBG (3, "lock_parport\n");
 | |
| 
 | |
| #ifdef HAVE_LINUX_PPDEV_H
 | |
|   fd = sanei_umax_pp_getparport ();
 | |
|   if ((fd > 0) && (!locked))
 | |
|     {
 | |
|       if (ioctl (sanei_umax_pp_getparport (), PPCLAIM))
 | |
|         {
 | |
|           return UMAX1220P_BUSY;
 | |
|         }
 | |
| #ifdef PPGETMODE
 | |
|       if (ioctl (fd, PPGETMODE, &exmode))
 | |
|         exmode = IEEE1284_MODE_COMPAT;
 | |
|       if (ioctl (fd, PPGETFLAGS, &exflags))
 | |
|         exflags = 0;
 | |
| #endif
 | |
|       mode = IEEE1284_MODE_EPP;
 | |
|       ioctl (fd, PPNEGOT, &mode);
 | |
|       ioctl (fd, PPSETMODE, &mode);
 | |
|       locked = 1;
 | |
|     }
 | |
| #else
 | |
|   locked = 1;
 | |
| #endif
 | |
|   return UMAX1220P_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* this function release parport */
 | |
| static int
 | |
| unlock_parport (void)
 | |
| {
 | |
| #ifdef HAVE_LINUX_PPDEV_H
 | |
|   int fd, mode;
 | |
| 
 | |
|   fd = sanei_umax_pp_getparport ();
 | |
|   if ((fd > 0) && (locked))
 | |
|     {
 | |
|       mode = IEEE1284_MODE_COMPAT;
 | |
|       ioctl (fd, PPNEGOT, &mode);
 | |
|       ioctl (fd, PPSETMODE, &exmode);
 | |
| #ifdef PPSETFLAGS
 | |
|       ioctl (fd, PPSETFLAGS, &exflags);
 | |
| #endif
 | |
|       ioctl (fd, PPRELEASE);
 | |
|       locked = 1;
 | |
|     }
 | |
| #endif
 | |
|   DBG (3, "unlock_parport\n");
 | |
|   locked = 0;
 | |
|   return UMAX1220P_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /* 
 | |
|  *
 | |
|  *  This function recognize the scanner model by sending an image
 | |
|  * filter command. 1220P will use it as is, but 2000P will return
 | |
|  * it back modified.
 | |
|  *
 | |
|  */
 | |
| int
 | |
| sanei_umax_pp_model (int port, int *model)
 | |
| {
 | |
|   int recover = 0, rc;
 | |
| 
 | |
|   /* set up port */
 | |
|   DBG (3, "sanei_umax_pp_model\n");
 | |
|   sanei_umax_pp_setport (port);
 | |
|   if (lock_parport () == UMAX1220P_BUSY)
 | |
|     return UMAX1220P_BUSY;
 | |
| 
 | |
|   /* init transport layer */
 | |
|   /* 0: failed
 | |
|      1: success
 | |
|      2: retry
 | |
|      3: busy
 | |
|    */
 | |
|   do
 | |
|     {
 | |
|       rc = sanei_umax_pp_initTransport (recover);
 | |
|     }
 | |
|   while (rc == 2);
 | |
| 
 | |
|   if (rc == 3)
 | |
|     {
 | |
|       unlock_parport ();
 | |
|       return UMAX1220P_BUSY;
 | |
|     }
 | |
|   if (rc != 1)
 | |
|     {
 | |
|       DBG (0, "sanei_umax_pp_initTransport() failed (%s:%d)\n", __FILE__,
 | |
|            __LINE__);
 | |
|       unlock_parport ();
 | |
|       return UMAX1220P_TRANSPORT_FAILED;
 | |
|     }
 | |
| 
 | |
|   /* check model only, and if only none given in conf file */
 | |
|   if (!sanei_umax_pp_getastra ())
 | |
|     {
 | |
|       rc = sanei_umax_pp_checkModel ();
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       rc = sanei_umax_pp_getastra ();
 | |
|     }
 | |
|   sanei_umax_pp_endSession ();
 | |
|   unlock_parport ();
 | |
|   if (rc < 600)
 | |
|     {
 | |
|       DBG (0, "sanei_umax_pp_CheckModel() failed (%s:%d)\n", __FILE__,
 | |
|            __LINE__);
 | |
|       return UMAX1220P_PROBE_FAILED;
 | |
|     }
 | |
|   *model = rc;
 | |
| 
 | |
| 
 | |
|   /* OK */
 | |
|   return UMAX1220P_OK;
 | |
| }
 | |
| 
 | |
| int
 | |
| sanei_umax_pp_attach (int port, char *name)
 | |
| {
 | |
|   int recover = 0;
 | |
| 
 | |
|   /* set up port */
 | |
|   if (name == NULL)
 | |
|     {
 | |
|       DBG (3, "sanei_umax_pp_attach(%d,NULL)\n", port);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       DBG (3, "sanei_umax_pp_attach(%d,%s)\n", port, name);
 | |
|     }
 | |
| 
 | |
|   sanei_umax_pp_setport (port);
 | |
|   if (sanei_umax_pp_initPort (port, name) != 1)
 | |
|     return UMAX1220P_PROBE_FAILED;
 | |
| 
 | |
|   /* init port locks the port, so we flag that */
 | |
|   locked = 1;
 | |
| 
 | |
|   if (sanei_umax_pp_probeScanner (recover) != 1)
 | |
|     {
 | |
|       if (recover)
 | |
|         {
 | |
|           sanei_umax_pp_initTransport (recover);
 | |
|           sanei_umax_pp_endSession ();
 | |
|           if (sanei_umax_pp_probeScanner (recover) != 1)
 | |
|             {
 | |
|               DBG (0, "Recover failed ....\n");
 | |
|               unlock_parport ();
 | |
|               return UMAX1220P_PROBE_FAILED;
 | |
|             }
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|           unlock_parport ();
 | |
|           return UMAX1220P_PROBE_FAILED;
 | |
|         }
 | |
|     }
 | |
|   sanei_umax_pp_endSession ();
 | |
|   unlock_parport ();
 | |
| 
 | |
| 
 | |
|   /* OK */
 | |
|   return UMAX1220P_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| sanei_umax_pp_open (int port, char *name)
 | |
| {
 | |
|   int rc;
 | |
|   int recover = 0;
 | |
| 
 | |
|   /* set up port */
 | |
|   DBG (3, "sanei_umax_pp_open\n");
 | |
| 
 | |
|   if (name == NULL)
 | |
|     sanei_umax_pp_setport (port);
 | |
| 
 | |
|   if (lock_parport () == UMAX1220P_BUSY)
 | |
|     return UMAX1220P_BUSY;
 | |
| 
 | |
|   /* init transport layer */
 | |
|   /* 0: failed
 | |
|      1: success
 | |
|      2: retry
 | |
|      3: scanner busy
 | |
|    */
 | |
|   do
 | |
|     {
 | |
|       rc = sanei_umax_pp_initTransport (recover);
 | |
|     }
 | |
|   while (rc == 2);
 | |
| 
 | |
|   if (rc == 3)
 | |
|     {
 | |
|       unlock_parport ();
 | |
|       return UMAX1220P_BUSY;
 | |
|     }
 | |
| 
 | |
|   if (rc != 1)
 | |
|     {
 | |
| 
 | |
|       DBG (0, "sanei_umax_pp_initTransport() failed (%s:%d)\n", __FILE__,
 | |
|            __LINE__);
 | |
|       unlock_parport ();
 | |
|       return UMAX1220P_TRANSPORT_FAILED;
 | |
|     }
 | |
|   /* init scanner */
 | |
|   if (sanei_umax_pp_initScanner (recover) == 0)
 | |
|     {
 | |
|       DBG (0, "sanei_umax_pp_initScanner() failed (%s:%d)\n", __FILE__,
 | |
|            __LINE__);
 | |
|       sanei_umax_pp_endSession ();
 | |
|       unlock_parport ();
 | |
|       return UMAX1220P_SCANNER_FAILED;
 | |
|     }
 | |
| 
 | |
|   /* OK */
 | |
|   unlock_parport ();
 | |
|   return UMAX1220P_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| sanei_umax_pp_cancel (void)
 | |
| {
 | |
|   DBG (3, "sanei_umax_pp_cancel\n");
 | |
|   if (lock_parport () == UMAX1220P_BUSY)
 | |
|     return UMAX1220P_BUSY;
 | |
| 
 | |
|   /* maybe EPAT reset here if exists */
 | |
|   sanei_umax_pp_cmdSync (0xC2);
 | |
|   sanei_umax_pp_cmdSync (0x00);
 | |
|   sanei_umax_pp_cmdSync (0x00);
 | |
|   if (sanei_umax_pp_park () == 0)
 | |
|     {
 | |
|       DBG (0, "sanei_umax_pp_park failed !!! (%s:%d)\n", __FILE__, __LINE__);
 | |
|       unlock_parport ();
 | |
|       return UMAX1220P_PARK_FAILED;
 | |
|     }
 | |
|   /* endSession() cancels any pending command  */
 | |
|   /* such as parking ...., so we only return   */
 | |
|   unlock_parport ();
 | |
|   return UMAX1220P_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| int
 | |
| sanei_umax_pp_start (int x, int y, int width, int height, int dpi, int color,
 | |
|                      int autoset,
 | |
|                      int gain, int offset, int *rbpp, int *rtw,
 | |
|                      int *rth)
 | |
| {
 | |
|   int col = BW_MODE;
 | |
| 
 | |
|   DBG (3, "sanei_umax_pp_start\n");
 | |
|   if (lock_parport () == UMAX1220P_BUSY)
 | |
|     return UMAX1220P_BUSY;
 | |
|   /* end session isn't done by cancel any more */
 | |
|   sanei_umax_pp_endSession ();
 | |
| 
 | |
|   if (autoset)
 | |
|     sanei_umax_pp_setauto (1);
 | |
|   else
 | |
|     sanei_umax_pp_setauto (0);
 | |
| 
 | |
|   switch (color)
 | |
|     {
 | |
|     case 0:
 | |
|       col = BW2_MODE;
 | |
|       break;
 | |
|     case 1:
 | |
|       col = BW_MODE;
 | |
|       break;
 | |
|     case 2:
 | |
|       col = RGB_MODE;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|   if (sanei_umax_pp_startScan
 | |
|       (x + sanei_umax_pp_getLeft (), y, width, height, dpi, col, gain,
 | |
|        offset, rbpp, rtw, rth) != 1)
 | |
|     {
 | |
|       sanei_umax_pp_endSession ();
 | |
|       unlock_parport ();
 | |
|       return UMAX1220P_START_FAILED;
 | |
|     }
 | |
|   unlock_parport ();
 | |
|   return UMAX1220P_OK;
 | |
| }
 | |
| 
 | |
| int
 | |
| sanei_umax_pp_read (long len, int window, int dpi, int last,
 | |
|                     unsigned char *buffer)
 | |
| {
 | |
|   int read = 0;
 | |
|   int bytes;
 | |
| 
 | |
|   DBG (3, "sanei_umax_pp_read\n");
 | |
|   if (lock_parport () == UMAX1220P_BUSY)
 | |
|     return UMAX1220P_BUSY;
 | |
| 
 | |
|   /* since 610P may override len and last to meet its */
 | |
|   /* hardware requirements, we have to loop until we  */
 | |
|   /* have all the data                                */
 | |
|   while (read < len)
 | |
|     {
 | |
|       bytes =
 | |
|         sanei_umax_pp_readBlock (len - read, window, dpi, last,
 | |
|                                  buffer + read);
 | |
|       if (bytes == 0)
 | |
|         {
 | |
|           sanei_umax_pp_endSession ();
 | |
|           return UMAX1220P_READ_FAILED;
 | |
|         }
 | |
|       read += bytes;
 | |
|     }
 | |
|   unlock_parport ();
 | |
|   return UMAX1220P_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| int
 | |
| sanei_umax_pp_lamp (int on)
 | |
| {
 | |
|   /* init transport layer */
 | |
|   DBG (3, "sanei_umax_pp_lamp\n");
 | |
| 
 | |
|   /* no lamp support for 610P ... */
 | |
|   if (sanei_umax_pp_getastra () < 1210)
 | |
|     return UMAX1220P_OK;
 | |
| 
 | |
|   if (lock_parport () == UMAX1220P_BUSY)
 | |
|     return UMAX1220P_BUSY;
 | |
| 
 | |
|   if (sanei_umax_pp_setLamp (on) == 0)
 | |
|     {
 | |
|       DBG (0, "Setting lamp state failed!\n");
 | |
|     }
 | |
| 
 | |
|   unlock_parport ();
 | |
|   return UMAX1220P_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| int
 | |
| sanei_umax_pp_status (void)
 | |
| {
 | |
|   int status;
 | |
| 
 | |
|   DBG (3, "sanei_umax_pp_status\n");
 | |
|   if (lock_parport () == UMAX1220P_BUSY)
 | |
|     return UMAX1220P_BUSY;
 | |
|   /* check if head is at home */
 | |
|   sanei_umax_pp_cmdSync (0x40);
 | |
|   status = sanei_umax_pp_scannerStatus ();
 | |
|   unlock_parport ();
 | |
|   DBG (8, "sanei_umax_pp_status=0x%02X\n", status);
 | |
|   if (((status & ASIC_BIT) != 0x00)||((status & MOTOR_BIT) == 0x00))
 | |
|     return UMAX1220P_BUSY;
 | |
| 
 | |
|   return UMAX1220P_OK;
 | |
| }
 | |
| 
 | |
| int
 | |
| sanei_umax_pp_close ()
 | |
| {
 | |
| #ifdef HAVE_LINUX_PPDEV_H
 | |
|   int fd;
 | |
| #endif
 | |
| 
 | |
|   DBG (3, "sanei_umax_pp_close\n");
 | |
| 
 | |
|   lock_parport ();
 | |
|   sanei_umax_pp_endSession ();
 | |
|   unlock_parport ();
 | |
| 
 | |
| #ifdef HAVE_LINUX_PPDEV_H
 | |
|   fd = sanei_umax_pp_getparport ();
 | |
|   if (fd > 0)
 | |
|     {
 | |
|       close (fd);
 | |
|       sanei_umax_pp_setparport (0);
 | |
|     }
 | |
| #endif
 | |
|   return UMAX1220P_OK;
 | |
| }
 |