kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			2060 wiersze
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			2060 wiersze
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
/* sane - Scanner Access Now Easy.
 | 
						|
   Copyright (C) 2000-2003 Jochen Eisinger <jochen.eisinger@gmx.net>
 | 
						|
   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, see <https://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
   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 the hardware driver scanners using a 300dpi CCD */
 | 
						|
 | 
						|
#include "mustek_pp_ccd300.h"
 | 
						|
 | 
						|
#define MUSTEK_PP_CCD300	4
 | 
						|
 | 
						|
static void config_ccd_101x (Mustek_pp_Handle * dev);
 | 
						|
static void config_ccd (Mustek_pp_Handle * dev);
 | 
						|
static void lamp (Mustek_pp_Handle * dev, int lamp_on);
 | 
						|
 | 
						|
#define CCD300_ASIC1013		0xa8
 | 
						|
#define CCD300_ASIC1015		0xa5
 | 
						|
 | 
						|
#define CCD300_CHANNEL_RED		0
 | 
						|
#define CCD300_CHANNEL_GREEN		1
 | 
						|
#define CCD300_CHANNEL_BLUE		2
 | 
						|
#define CCD300_CHANNEL_GRAY		1
 | 
						|
 | 
						|
#define CCD300_MAXHSIZE		2600
 | 
						|
#define CCD300_MAXVSIZE		3500
 | 
						|
 | 
						|
/*
 | 
						|
 *  Here starts the driver code for the different chipsets
 | 
						|
 *
 | 
						|
 *  The 1013 & 1015 chipsets share large portions of the code. This
 | 
						|
 *  shared functions end with _101x.
 | 
						|
 */
 | 
						|
 | 
						|
static const u_char chan_codes_1013[] = { 0x82, 0x42, 0xC2 };
 | 
						|
static const u_char chan_codes_1015[] = { 0x80, 0x40, 0xC0 };
 | 
						|
static const u_char fullstep[] = { 0x09, 0x0C, 0x06, 0x03 };
 | 
						|
static const u_char halfstep[] = { 0x02, 0x03, 0x01, 0x09,
 | 
						|
  0x08, 0x0C, 0x04, 0x06
 | 
						|
};
 | 
						|
static const u_char voltages[4][3] = { {0x5C, 0x5A, 0x63},
 | 
						|
{0xE6, 0xB4, 0xBE},
 | 
						|
{0xB4, 0xB4, 0xB4},
 | 
						|
{0x64, 0x50, 0x64}
 | 
						|
};
 | 
						|
 | 
						|
/* Forward declarations of 1013/1015 functions */
 | 
						|
static void set_ccd_channel_1013 (Mustek_pp_Handle * dev, int channel);
 | 
						|
static void motor_backward_1013 (Mustek_pp_Handle * dev);
 | 
						|
static void return_home_1013 (Mustek_pp_Handle * dev);
 | 
						|
static void motor_forward_1013 (Mustek_pp_Handle * dev);
 | 
						|
static void config_ccd_1013 (Mustek_pp_Handle * dev);
 | 
						|
 | 
						|
static void set_ccd_channel_1015 (Mustek_pp_Handle * dev, int channel);
 | 
						|
/* static void motor_backward_1015 (Mustek_pp_Handle * dev); */
 | 
						|
static void return_home_1015 (Mustek_pp_Handle * dev, SANE_Bool nowait);
 | 
						|
static void motor_forward_1015 (Mustek_pp_Handle * dev);
 | 
						|
static void config_ccd_1015 (Mustek_pp_Handle * dev);
 | 
						|
 | 
						|
 | 
						|
/* These functions are common to all 1013/1015 chipsets */
 | 
						|
 | 
						|
static void
 | 
						|
set_led (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6,
 | 
						|
			 (priv->motor_step % 5 == 0 ? 0x03 : 0x13));
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
set_sti (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 3, 0);
 | 
						|
  priv->bank_count++;
 | 
						|
  priv->bank_count &= 7;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
get_bank_count (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  u_char val;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  sanei_pa4s2_readbegin (dev->fd, 3);
 | 
						|
  sanei_pa4s2_readbyte (dev->fd, &val);
 | 
						|
  sanei_pa4s2_readend (dev->fd);
 | 
						|
 | 
						|
  priv->bank_count = (val & 0x07);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
reset_bank_count (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 7);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
wait_bank_change (Mustek_pp_Handle * dev, int bankcount, int niceload)
 | 
						|
{
 | 
						|
  struct timeval start, end;
 | 
						|
  unsigned long diff;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
  int first_time = 1;
 | 
						|
 | 
						|
  gettimeofday (&start, NULL);
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
      if ((niceload == 0) && (first_time == 0))
 | 
						|
	{
 | 
						|
	  usleep (1);		/* could be as well sched_yield */
 | 
						|
	  first_time = 0;
 | 
						|
	}
 | 
						|
      get_bank_count (dev);
 | 
						|
 | 
						|
      gettimeofday (&end, NULL);
 | 
						|
      diff = (end.tv_sec * 1000 + end.tv_usec / 1000) -
 | 
						|
	(start.tv_sec * 1000 + start.tv_usec / 1000);
 | 
						|
 | 
						|
    }
 | 
						|
  while ((priv->bank_count != bankcount) && (diff < priv->wait_bank));
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
set_dpi_value (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  u_char val = 0;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x80);
 | 
						|
 | 
						|
  switch (priv->hwres)
 | 
						|
    {
 | 
						|
    case 100:
 | 
						|
      val = 0x00;
 | 
						|
      break;
 | 
						|
    case 200:
 | 
						|
      val = 0x10;
 | 
						|
      break;
 | 
						|
    case 300:
 | 
						|
      val = 0x20;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
  if (priv->ccd_type == 1)
 | 
						|
    val |= 0x01;
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 5, val);
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x00);
 | 
						|
 | 
						|
  DBG (5, "set_dpi_value: value 0x%02x\n", val);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
set_line_adjust (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  int adjustline;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  adjustline = (dev->bottomX - dev->topX) * priv->hwres / 300;
 | 
						|
  priv->adjustskip = priv->adjustskip * priv->hwres / 300;
 | 
						|
 | 
						|
  DBG (5, "set_line_adjust: ppl %u (%u), adjust %u, skip %u\n",
 | 
						|
       dev->params.pixels_per_line, (dev->bottomX - dev->topX), adjustline,
 | 
						|
       priv->adjustskip);
 | 
						|
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x11);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 5, (adjustline + priv->adjustskip) >> 8);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x21);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 5, (adjustline + priv->adjustskip) & 0xFF);
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x01);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
set_lamp (Mustek_pp_Handle * dev, int lamp_on)
 | 
						|
{
 | 
						|
 | 
						|
  int ctr;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0xC3);
 | 
						|
 | 
						|
  for (ctr = 0; ctr < 3; ctr++)
 | 
						|
    {
 | 
						|
      sanei_pa4s2_writebyte (dev->fd, 6, (lamp_on ? 0x47 : 0x57));
 | 
						|
      sanei_pa4s2_writebyte (dev->fd, 6, 0x77);
 | 
						|
    }
 | 
						|
 | 
						|
  priv->motor_step = lamp_on;
 | 
						|
 | 
						|
  set_led (dev);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
send_voltages (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
 | 
						|
  int voltage, sel = 8, ctr;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  switch (priv->ccd_type)
 | 
						|
    {
 | 
						|
    case 0:
 | 
						|
      voltage = 0;
 | 
						|
      break;
 | 
						|
    case 1:
 | 
						|
      voltage = 1;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      voltage = 2;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  for (ctr = 0; ctr < 3; ctr++)
 | 
						|
    {
 | 
						|
 | 
						|
      sel <<= 1;
 | 
						|
      sanei_pa4s2_writebyte (dev->fd, 6, sel);
 | 
						|
      sanei_pa4s2_writebyte (dev->fd, 5, voltages[voltage][ctr]);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x00);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
compar (const void *a, const void *b)
 | 
						|
{
 | 
						|
  return (signed int) (*(const SANE_Byte *) a) -
 | 
						|
    (signed int) (*(const SANE_Byte *) b);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
set_ccd_channel_101x (Mustek_pp_Handle * dev, int channel)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
  switch (priv->asic)
 | 
						|
    {
 | 
						|
    case CCD300_ASIC1013:
 | 
						|
      set_ccd_channel_1013 (dev, channel);
 | 
						|
      break;
 | 
						|
 | 
						|
    case CCD300_ASIC1015:
 | 
						|
      set_ccd_channel_1015 (dev, channel);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
motor_forward_101x (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
  switch (priv->asic)
 | 
						|
    {
 | 
						|
    case CCD300_ASIC1013:
 | 
						|
      motor_forward_1013 (dev);
 | 
						|
      break;
 | 
						|
 | 
						|
    case CCD300_ASIC1015:
 | 
						|
      motor_forward_1015 (dev);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
motor_backward_101x (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
  switch (priv->asic)
 | 
						|
    {
 | 
						|
    case CCD300_ASIC1013:
 | 
						|
      motor_backward_1013 (dev);
 | 
						|
      break;
 | 
						|
 | 
						|
    case CCD300_ASIC1015:
 | 
						|
/*      motor_backward_1015 (dev); */
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
move_motor_101x (Mustek_pp_Handle * dev, int forward)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
  if (forward == SANE_TRUE)
 | 
						|
    motor_forward_101x (dev);
 | 
						|
  else
 | 
						|
    motor_backward_101x (dev);
 | 
						|
 | 
						|
  wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
  reset_bank_count (dev);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
config_ccd_101x (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
  switch (priv->asic)
 | 
						|
    {
 | 
						|
    case CCD300_ASIC1013:
 | 
						|
      config_ccd_1013 (dev);
 | 
						|
      break;
 | 
						|
 | 
						|
    case CCD300_ASIC1015:
 | 
						|
      config_ccd_1015 (dev);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
read_line_101x (Mustek_pp_Handle * dev, SANE_Byte * buf, SANE_Int pixel,
 | 
						|
		SANE_Int RefBlack, SANE_Byte * calib, SANE_Int * gamma)
 | 
						|
{
 | 
						|
 | 
						|
  SANE_Byte *cal = calib;
 | 
						|
  u_char color;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
  int ctr, skips = priv->adjustskip + 1, cval;
 | 
						|
 | 
						|
  if (pixel <= 0)
 | 
						|
    return;
 | 
						|
 | 
						|
  sanei_pa4s2_readbegin (dev->fd, 1);
 | 
						|
 | 
						|
 | 
						|
  if (priv->hwres == dev->res)
 | 
						|
    {
 | 
						|
 | 
						|
      while (skips--)
 | 
						|
	sanei_pa4s2_readbyte (dev->fd, &color);
 | 
						|
 | 
						|
      for (ctr = 0; ctr < pixel; ctr++)
 | 
						|
	{
 | 
						|
 | 
						|
	  sanei_pa4s2_readbyte (dev->fd, &color);
 | 
						|
 | 
						|
	  cval = color;
 | 
						|
 | 
						|
	  if (cval < RefBlack)
 | 
						|
	    cval = 0;
 | 
						|
	  else
 | 
						|
	    cval -= RefBlack;
 | 
						|
 | 
						|
	  if (cal)
 | 
						|
	    {
 | 
						|
	      if (cval >= cal[ctr])
 | 
						|
		cval = 0xFF;
 | 
						|
	      else
 | 
						|
		{
 | 
						|
		  cval <<= 8;
 | 
						|
		  cval /= (int) cal[ctr];
 | 
						|
		}
 | 
						|
	    }
 | 
						|
 | 
						|
	  if (gamma)
 | 
						|
	    cval = gamma[cval];
 | 
						|
 | 
						|
	  buf[ctr] = cval;
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
 | 
						|
      int pos = 0, bpos = 0;
 | 
						|
 | 
						|
      while (skips--)
 | 
						|
	sanei_pa4s2_readbyte (dev->fd, &color);
 | 
						|
 | 
						|
      ctr = 0;
 | 
						|
 | 
						|
      do
 | 
						|
	{
 | 
						|
 | 
						|
	  sanei_pa4s2_readbyte (dev->fd, &color);
 | 
						|
 | 
						|
	  cval = color;
 | 
						|
 | 
						|
	  if (ctr < (pos >> SANE_FIXED_SCALE_SHIFT))
 | 
						|
	    {
 | 
						|
	      ctr++;
 | 
						|
	      continue;
 | 
						|
	    }
 | 
						|
 | 
						|
	  ctr++;
 | 
						|
	  pos += priv->res_step;
 | 
						|
 | 
						|
 | 
						|
	  if (cval < RefBlack)
 | 
						|
	    cval = 0;
 | 
						|
	  else
 | 
						|
	    cval -= RefBlack;
 | 
						|
 | 
						|
	  if (cal)
 | 
						|
	    {
 | 
						|
	      if (cval >= cal[bpos])
 | 
						|
		cval = 0xFF;
 | 
						|
	      else
 | 
						|
		{
 | 
						|
		  cval <<= 8;
 | 
						|
		  cval /= (int) cal[bpos];
 | 
						|
		}
 | 
						|
	    }
 | 
						|
 | 
						|
	  if (gamma)
 | 
						|
	    cval = gamma[cval];
 | 
						|
 | 
						|
	  buf[bpos++] = cval;
 | 
						|
 | 
						|
	}
 | 
						|
      while (bpos < pixel);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  sanei_pa4s2_readend (dev->fd);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
read_average_line_101x (Mustek_pp_Handle * dev, SANE_Byte * buf, int pixel,
 | 
						|
			int RefBlack)
 | 
						|
{
 | 
						|
 | 
						|
  SANE_Byte lbuf[4][CCD300_MAXHSIZE * 2];
 | 
						|
  int ctr, sum;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  for (ctr = 0; ctr < 4; ctr++)
 | 
						|
    {
 | 
						|
 | 
						|
      wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
      read_line_101x (dev, lbuf[ctr], pixel, RefBlack, NULL, NULL);
 | 
						|
      reset_bank_count (dev);
 | 
						|
      if (ctr < 3)
 | 
						|
	set_sti (dev);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  for (ctr = 0; ctr < pixel; ctr++)
 | 
						|
    {
 | 
						|
 | 
						|
      sum = lbuf[0][ctr] + lbuf[1][ctr] + lbuf[2][ctr] + lbuf[3][ctr];
 | 
						|
 | 
						|
      buf[ctr] = (sum / 4);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
find_black_side_edge_101x (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  SANE_Byte buf[CCD300_MAXHSIZE * 2];
 | 
						|
  SANE_Byte blackposition[5];
 | 
						|
  int pos = 0, ctr, blackpos;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
 | 
						|
  for (ctr = 0; ctr < 20; ctr++)
 | 
						|
    {
 | 
						|
 | 
						|
      motor_forward_101x (dev);
 | 
						|
      wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
      read_line_101x (dev, buf, CCD300_MAXHSIZE, 0, NULL, NULL);
 | 
						|
      reset_bank_count (dev);
 | 
						|
 | 
						|
      priv->ref_black = priv->ref_red = priv->ref_green = priv->ref_blue =
 | 
						|
	buf[0];
 | 
						|
 | 
						|
      blackpos = CCD300_MAXHSIZE / 4;
 | 
						|
 | 
						|
      while ((abs (buf[blackpos] - buf[0]) >= 15) && (blackpos > 0))
 | 
						|
	blackpos--;
 | 
						|
 | 
						|
      if (blackpos > 1)
 | 
						|
	blackposition[pos++] = blackpos;
 | 
						|
 | 
						|
      if (pos == 5)
 | 
						|
	break;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  blackpos = 0;
 | 
						|
 | 
						|
  for (ctr = 0; ctr < pos; ctr++)
 | 
						|
    if (blackposition[ctr] > blackpos)
 | 
						|
      blackpos = blackposition[ctr];
 | 
						|
 | 
						|
  if (blackpos < 0x66)
 | 
						|
    blackpos = 0x6A;
 | 
						|
 | 
						|
  priv->blackpos = blackpos;
 | 
						|
  priv->saved_skipcount = (blackpos + 12) & 0xFF;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
min_color_levels_101x (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
 | 
						|
  SANE_Byte buf[CCD300_MAXHSIZE * 2];
 | 
						|
  int ctr, sum = 0;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  for (ctr = 0; ctr < 8; ctr++)
 | 
						|
    {
 | 
						|
 | 
						|
      set_ccd_channel_101x (dev, CCD300_CHANNEL_RED);
 | 
						|
      set_sti (dev);
 | 
						|
      wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
 | 
						|
      read_line_101x (dev, buf, CCD300_MAXHSIZE, 0, NULL, NULL);
 | 
						|
 | 
						|
      reset_bank_count (dev);
 | 
						|
 | 
						|
      sum += buf[3];
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  priv->ref_red = sum / 8;
 | 
						|
 | 
						|
  sum = 0;
 | 
						|
 | 
						|
  for (ctr = 0; ctr < 8; ctr++)
 | 
						|
    {
 | 
						|
 | 
						|
      set_ccd_channel_101x (dev, CCD300_CHANNEL_GREEN);
 | 
						|
      set_sti (dev);
 | 
						|
      wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
 | 
						|
      read_line_101x (dev, buf, CCD300_MAXHSIZE, 0, NULL, NULL);
 | 
						|
 | 
						|
      reset_bank_count (dev);
 | 
						|
 | 
						|
      sum += buf[3];
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  priv->ref_green = sum / 8;
 | 
						|
 | 
						|
  sum = 0;
 | 
						|
 | 
						|
  for (ctr = 0; ctr < 8; ctr++)
 | 
						|
    {
 | 
						|
 | 
						|
      set_ccd_channel_101x (dev, CCD300_CHANNEL_BLUE);
 | 
						|
      set_sti (dev);
 | 
						|
      wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
 | 
						|
      read_line_101x (dev, buf, CCD300_MAXHSIZE, 0, NULL, NULL);
 | 
						|
 | 
						|
      reset_bank_count (dev);
 | 
						|
 | 
						|
      sum += buf[3];
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  priv->ref_blue = sum / 8;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
max_color_levels_101x (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
 | 
						|
  int ctr, line, sum;
 | 
						|
  SANE_Byte rbuf[32][CCD300_MAXHSIZE * 2];
 | 
						|
  SANE_Byte gbuf[32][CCD300_MAXHSIZE * 2];
 | 
						|
  SANE_Byte bbuf[32][CCD300_MAXHSIZE * 2];
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  SANE_Byte maxbuf[32];
 | 
						|
 | 
						|
  for (ctr = 0; ctr < 32; ctr++)
 | 
						|
    {
 | 
						|
 | 
						|
      if (dev->mode == MODE_COLOR)
 | 
						|
	{
 | 
						|
 | 
						|
	  set_ccd_channel_101x (dev, CCD300_CHANNEL_RED);
 | 
						|
	  motor_forward_101x (dev);
 | 
						|
 | 
						|
	  read_average_line_101x (dev, rbuf[ctr], dev->params.pixels_per_line,
 | 
						|
				  priv->ref_red);
 | 
						|
 | 
						|
	  set_ccd_channel_101x (dev, CCD300_CHANNEL_GREEN);
 | 
						|
	  set_sti (dev);
 | 
						|
 | 
						|
	  read_average_line_101x (dev, gbuf[ctr], dev->params.pixels_per_line,
 | 
						|
				  priv->ref_green);
 | 
						|
 | 
						|
	  set_ccd_channel_101x (dev, CCD300_CHANNEL_BLUE);
 | 
						|
	  set_sti (dev);
 | 
						|
 | 
						|
	  read_average_line_101x (dev, bbuf[ctr], dev->params.pixels_per_line,
 | 
						|
				  priv->ref_blue);
 | 
						|
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
 | 
						|
	  priv->channel = CCD300_CHANNEL_GRAY;
 | 
						|
 | 
						|
	  motor_forward_101x (dev);
 | 
						|
 | 
						|
	  read_average_line_101x (dev, gbuf[ctr], dev->params.pixels_per_line,
 | 
						|
				  priv->ref_black);
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
  for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
 | 
						|
    {
 | 
						|
      for (line = 0; line < 32; line++)
 | 
						|
	maxbuf[line] = gbuf[line][ctr];
 | 
						|
 | 
						|
      qsort (maxbuf, 32, sizeof (maxbuf[0]), compar);
 | 
						|
 | 
						|
      sum = maxbuf[4] + maxbuf[5] + maxbuf[6] + maxbuf[7];
 | 
						|
 | 
						|
      priv->calib_g[ctr] = sum / 4;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  if (dev->mode == MODE_COLOR)
 | 
						|
    {
 | 
						|
 | 
						|
      for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
 | 
						|
	{
 | 
						|
	  for (line = 0; line < 32; line++)
 | 
						|
	    maxbuf[line] = rbuf[line][ctr];
 | 
						|
 | 
						|
	  qsort (maxbuf, 32, sizeof (maxbuf[0]), compar);
 | 
						|
 | 
						|
	  sum = maxbuf[4] + maxbuf[5] + maxbuf[6] + maxbuf[7];
 | 
						|
 | 
						|
	  priv->calib_r[ctr] = sum / 4;
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
      for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
 | 
						|
	{
 | 
						|
	  for (line = 0; line < 32; line++)
 | 
						|
	    maxbuf[line] = bbuf[line][ctr];
 | 
						|
 | 
						|
	  qsort (maxbuf, 32, sizeof (maxbuf[0]), compar);
 | 
						|
 | 
						|
	  sum = maxbuf[4] + maxbuf[5] + maxbuf[6] + maxbuf[7];
 | 
						|
 | 
						|
	  priv->calib_b[ctr] = sum / 4;
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
find_black_top_edge_101x (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
 | 
						|
  int lines = 0, ctr, pos;
 | 
						|
  SANE_Byte buf[CCD300_MAXHSIZE * 2];
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  priv->channel = CCD300_CHANNEL_GRAY;
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
 | 
						|
      motor_forward_101x (dev);
 | 
						|
      wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
 | 
						|
      read_line_101x (dev, buf, CCD300_MAXHSIZE, priv->ref_black, NULL, NULL);
 | 
						|
 | 
						|
      reset_bank_count (dev);
 | 
						|
 | 
						|
      pos = 0;
 | 
						|
 | 
						|
      for (ctr = priv->blackpos; ctr > priv->blackpos - 10; ctr--)
 | 
						|
	if (buf[ctr] <= 15)
 | 
						|
	  pos++;
 | 
						|
 | 
						|
    }
 | 
						|
  while ((pos >= 8) && (lines++ < 67));
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
calibrate_device_101x (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
 | 
						|
  int saved_ppl = dev->params.pixels_per_line, ctr;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  priv->saved_mode = dev->mode;
 | 
						|
  priv->saved_invert = dev->invert;
 | 
						|
  priv->saved_skipcount = priv->skipcount;
 | 
						|
  priv->saved_skipimagebyte = priv->skipimagebytes;
 | 
						|
  priv->saved_adjustskip = priv->adjustskip;
 | 
						|
  priv->saved_res = dev->res;
 | 
						|
  priv->saved_hwres = priv->hwres;
 | 
						|
  priv->saved_res_step = priv->res_step;
 | 
						|
  priv->saved_line_step = priv->line_step;
 | 
						|
  priv->saved_channel = priv->channel;
 | 
						|
 | 
						|
  dev->params.pixels_per_line = CCD300_MAXHSIZE;
 | 
						|
  priv->hwres = dev->res = 300;
 | 
						|
  dev->mode = MODE_GRAYSCALE;
 | 
						|
  priv->skipcount = priv->skipimagebytes = 0;
 | 
						|
  dev->invert = SANE_FALSE;
 | 
						|
  priv->channel = CCD300_CHANNEL_GRAY;
 | 
						|
 | 
						|
  config_ccd_101x (dev);
 | 
						|
  get_bank_count (dev);
 | 
						|
 | 
						|
  find_black_side_edge_101x (dev);
 | 
						|
 | 
						|
  for (ctr = 0; ctr < 4; ctr++)
 | 
						|
    move_motor_101x (dev, SANE_TRUE);
 | 
						|
 | 
						|
  dev->mode = priv->saved_mode;
 | 
						|
  dev->invert = priv->saved_invert;
 | 
						|
  priv->skipcount = priv->saved_skipcount;
 | 
						|
  priv->skipimagebytes = priv->saved_skipimagebyte;
 | 
						|
  priv->adjustskip = priv->saved_adjustskip;
 | 
						|
  dev->res = priv->saved_res;
 | 
						|
  priv->hwres = priv->saved_hwres;
 | 
						|
  priv->res_step = priv->saved_res_step;
 | 
						|
  priv->line_step = priv->saved_line_step;
 | 
						|
  priv->channel = priv->saved_channel;
 | 
						|
 | 
						|
  priv->hwres = dev->res = 300;
 | 
						|
  priv->skipcount = priv->skipimagebytes = 0;
 | 
						|
  dev->invert = SANE_FALSE;
 | 
						|
 | 
						|
  config_ccd_101x (dev);
 | 
						|
  get_bank_count (dev);
 | 
						|
 | 
						|
  if ((dev->mode == MODE_COLOR) && (priv->ccd_type != 0))
 | 
						|
    min_color_levels_101x (dev);
 | 
						|
 | 
						|
  dev->mode = priv->saved_mode;
 | 
						|
  dev->invert = priv->saved_invert;
 | 
						|
  priv->skipcount = priv->saved_skipcount;
 | 
						|
  priv->skipimagebytes = priv->saved_skipimagebyte;
 | 
						|
  priv->adjustskip = priv->saved_adjustskip;
 | 
						|
  dev->res = priv->saved_res;
 | 
						|
  priv->hwres = priv->saved_hwres;
 | 
						|
  priv->res_step = priv->saved_res_step;
 | 
						|
  priv->line_step = priv->saved_line_step;
 | 
						|
  priv->channel = priv->saved_channel;
 | 
						|
 | 
						|
  dev->params.pixels_per_line = saved_ppl;
 | 
						|
  dev->invert = SANE_FALSE;
 | 
						|
 | 
						|
  config_ccd_101x (dev);
 | 
						|
  get_bank_count (dev);
 | 
						|
 | 
						|
  max_color_levels_101x (dev);
 | 
						|
 | 
						|
  dev->params.pixels_per_line = CCD300_MAXHSIZE;
 | 
						|
  dev->mode = MODE_GRAYSCALE;
 | 
						|
  priv->hwres = dev->res = 300;
 | 
						|
  priv->skipcount = priv->skipimagebytes = 0;
 | 
						|
  dev->invert = SANE_FALSE;
 | 
						|
 | 
						|
  config_ccd_101x (dev);
 | 
						|
  get_bank_count (dev);
 | 
						|
 | 
						|
  find_black_top_edge_101x (dev);
 | 
						|
 | 
						|
  dev->mode = priv->saved_mode;
 | 
						|
  dev->invert = priv->saved_invert;
 | 
						|
  priv->skipcount = priv->saved_skipcount;
 | 
						|
  priv->skipimagebytes = priv->saved_skipimagebyte;
 | 
						|
  priv->adjustskip = priv->saved_adjustskip;
 | 
						|
  dev->res = priv->saved_res;
 | 
						|
  priv->hwres = priv->saved_hwres;
 | 
						|
  priv->res_step = priv->saved_res_step;
 | 
						|
  priv->line_step = priv->saved_line_step;
 | 
						|
  priv->channel = priv->saved_channel;
 | 
						|
 | 
						|
  dev->params.pixels_per_line = saved_ppl;
 | 
						|
 | 
						|
  config_ccd_101x (dev);
 | 
						|
  get_bank_count (dev);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
get_grayscale_line_101x (Mustek_pp_Handle * dev, SANE_Byte * buf)
 | 
						|
{
 | 
						|
 | 
						|
  int skips;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  priv->line_diff += SANE_FIX (300.0 / (float) dev->res);
 | 
						|
 | 
						|
  skips = (priv->line_diff >> SANE_FIXED_SCALE_SHIFT);
 | 
						|
 | 
						|
  while (--skips)
 | 
						|
    {
 | 
						|
      motor_forward_101x (dev);
 | 
						|
      wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
      reset_bank_count (dev);
 | 
						|
    }
 | 
						|
 | 
						|
  priv->line_diff &= 0xFFFF;
 | 
						|
 | 
						|
  motor_forward_101x (dev);
 | 
						|
  wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
 | 
						|
  read_line_101x (dev, buf, dev->params.pixels_per_line, priv->ref_black,
 | 
						|
		  priv->calib_g, NULL);
 | 
						|
 | 
						|
  reset_bank_count (dev);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
get_lineart_line_101x (Mustek_pp_Handle * dev, SANE_Byte * buf)
 | 
						|
{
 | 
						|
 | 
						|
  int ctr;
 | 
						|
  SANE_Byte gbuf[CCD300_MAXHSIZE * 2];
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  get_grayscale_line_101x (dev, gbuf);
 | 
						|
 | 
						|
  memset (buf, 0xFF, dev->params.bytes_per_line);
 | 
						|
 | 
						|
  for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
 | 
						|
    buf[ctr >> 3] ^= ((gbuf[ctr] > priv->bw) ? (1 << (7 - ctr % 8)) : 0);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
get_color_line_101x (Mustek_pp_Handle * dev, SANE_Byte * buf)
 | 
						|
{
 | 
						|
 | 
						|
  SANE_Byte *red, *blue, *src, *dest;
 | 
						|
  int gotline = 0, ctr;
 | 
						|
  int gored, goblue, gogreen;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
  int step = priv->line_step;
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
 | 
						|
      red = priv->red[priv->redline];
 | 
						|
      blue = priv->blue[priv->blueline];
 | 
						|
 | 
						|
      priv->ccd_line++;
 | 
						|
 | 
						|
      if ((priv->rdiff >> SANE_FIXED_SCALE_SHIFT) == priv->ccd_line)
 | 
						|
	{
 | 
						|
	  gored = 1;
 | 
						|
	  priv->rdiff += step;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	gored = 0;
 | 
						|
 | 
						|
      if ((priv->bdiff >> SANE_FIXED_SCALE_SHIFT) == priv->ccd_line)
 | 
						|
	{
 | 
						|
	  goblue = 1;
 | 
						|
	  priv->bdiff += step;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	goblue = 0;
 | 
						|
 | 
						|
      if ((priv->gdiff >> SANE_FIXED_SCALE_SHIFT) == priv->ccd_line)
 | 
						|
	{
 | 
						|
	  gogreen = 1;
 | 
						|
	  priv->gdiff += step;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	gogreen = 0;
 | 
						|
 | 
						|
      if (!gored && !goblue && !gogreen)
 | 
						|
	{
 | 
						|
	  motor_forward_101x (dev);
 | 
						|
	  wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
	  reset_bank_count (dev);
 | 
						|
	  if (priv->ccd_line >= (priv->line_step >> SANE_FIXED_SCALE_SHIFT))
 | 
						|
	    priv->redline = (priv->redline + 1) % priv->green_offs;
 | 
						|
	  if (priv->ccd_line >=
 | 
						|
	      priv->blue_offs + (priv->line_step >> SANE_FIXED_SCALE_SHIFT))
 | 
						|
	    priv->blueline = (priv->blueline + 1) % priv->blue_offs;
 | 
						|
	  continue;
 | 
						|
	}
 | 
						|
 | 
						|
      if (gored)
 | 
						|
	priv->channel = CCD300_CHANNEL_RED;
 | 
						|
      else if (goblue)
 | 
						|
	priv->channel = CCD300_CHANNEL_BLUE;
 | 
						|
      else
 | 
						|
	priv->channel = CCD300_CHANNEL_GREEN;
 | 
						|
 | 
						|
      motor_forward_101x (dev);
 | 
						|
      wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
 | 
						|
      if (priv->ccd_line >= priv->green_offs && gogreen)
 | 
						|
	{
 | 
						|
	  src = red;
 | 
						|
	  dest = buf;
 | 
						|
 | 
						|
	  for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
 | 
						|
	    {
 | 
						|
	      *dest = *src++;
 | 
						|
	      dest += 3;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
      if (gored)
 | 
						|
	{
 | 
						|
 | 
						|
	  read_line_101x (dev, red, dev->params.pixels_per_line,
 | 
						|
			  priv->ref_red, priv->calib_r, NULL);
 | 
						|
 | 
						|
	  reset_bank_count (dev);
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
      priv->redline = (priv->redline + 1) % priv->green_offs;
 | 
						|
 | 
						|
      if (priv->ccd_line >= priv->green_offs && gogreen)
 | 
						|
	{
 | 
						|
	  src = blue;
 | 
						|
	  dest = buf + 2;
 | 
						|
 | 
						|
 | 
						|
	  for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
 | 
						|
	    {
 | 
						|
	      *dest = *src++;
 | 
						|
	      dest += 3;
 | 
						|
	    }
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
      if (goblue)
 | 
						|
	{
 | 
						|
	  if (gored)
 | 
						|
	    {
 | 
						|
	      set_ccd_channel_101x (dev, CCD300_CHANNEL_BLUE);
 | 
						|
	      set_sti (dev);
 | 
						|
	      wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
	    }
 | 
						|
 | 
						|
	  read_line_101x (dev, blue, dev->params.pixels_per_line,
 | 
						|
			  priv->ref_blue, priv->calib_b, NULL);
 | 
						|
 | 
						|
	  reset_bank_count (dev);
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
      if (priv->ccd_line >=
 | 
						|
	  priv->blue_offs + (priv->line_step >> SANE_FIXED_SCALE_SHIFT))
 | 
						|
	priv->blueline = (priv->blueline + 1) % priv->blue_offs;
 | 
						|
 | 
						|
      if (gogreen)
 | 
						|
	{
 | 
						|
 | 
						|
	  if (gored || goblue)
 | 
						|
	    {
 | 
						|
	      set_ccd_channel_101x (dev, CCD300_CHANNEL_GREEN);
 | 
						|
	      set_sti (dev);
 | 
						|
	      wait_bank_change (dev, priv->bank_count, 1);
 | 
						|
	    }
 | 
						|
 | 
						|
	  read_line_101x (dev, priv->green, dev->params.pixels_per_line,
 | 
						|
			  priv->ref_green, priv->calib_g, NULL);
 | 
						|
 | 
						|
	  reset_bank_count (dev);
 | 
						|
 | 
						|
	  src = priv->green;
 | 
						|
	  dest = buf + 1;
 | 
						|
 | 
						|
	  for (ctr = 0; ctr < dev->params.pixels_per_line; ctr++)
 | 
						|
	    {
 | 
						|
	      *dest = *src++;
 | 
						|
	      dest += 3;
 | 
						|
	    }
 | 
						|
 | 
						|
	  gotline = 1;
 | 
						|
	}
 | 
						|
 | 
						|
    }
 | 
						|
  while (!gotline);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* these functions are for the 1013 chipset */
 | 
						|
 | 
						|
static void
 | 
						|
set_ccd_channel_1013 (Mustek_pp_Handle * dev, int channel)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
  priv->channel = channel;
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, chan_codes_1013[channel]);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
motor_backward_1013 (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  priv->motor_step++;
 | 
						|
  set_led (dev);
 | 
						|
 | 
						|
  if (priv->motor_phase > 3)
 | 
						|
    priv->motor_phase = 3;
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x62);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 5, fullstep[priv->motor_phase]);
 | 
						|
 | 
						|
  priv->motor_phase = (priv->motor_phase == 0 ? 3 : priv->motor_phase - 1);
 | 
						|
 | 
						|
  set_ccd_channel_1013 (dev, priv->channel);
 | 
						|
  set_sti (dev);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
return_home_1013 (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  u_char ishome;
 | 
						|
  int ctr;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  /* 1013 can't return home all alone, nowait ignored */
 | 
						|
 | 
						|
  for (ctr = 0; ctr < 4500; ctr++)
 | 
						|
    {
 | 
						|
 | 
						|
      /* check_is_home_1013 */
 | 
						|
      sanei_pa4s2_readbegin (dev->fd, 2);
 | 
						|
      sanei_pa4s2_readbyte (dev->fd, &ishome);
 | 
						|
      sanei_pa4s2_readend (dev->fd);
 | 
						|
 | 
						|
      /* yes, it should be is_not_home */
 | 
						|
      if ((ishome & 1) == 0)
 | 
						|
	break;
 | 
						|
 | 
						|
      motor_backward_1013 (dev);
 | 
						|
      wait_bank_change (dev, priv->bank_count, 0);
 | 
						|
      reset_bank_count (dev);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
motor_forward_1013 (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
 | 
						|
  int ctr;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  priv->motor_step++;
 | 
						|
  set_led (dev);
 | 
						|
 | 
						|
  for (ctr = 0; ctr < 2; ctr++)
 | 
						|
    {
 | 
						|
 | 
						|
      sanei_pa4s2_writebyte (dev->fd, 6, 0x62);
 | 
						|
      sanei_pa4s2_writebyte (dev->fd, 5, halfstep[priv->motor_phase]);
 | 
						|
 | 
						|
      priv->motor_phase =
 | 
						|
	(priv->motor_phase == 7 ? 0 : priv->motor_phase + 1);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  set_ccd_channel_1013 (dev, priv->channel);
 | 
						|
  set_sti (dev);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
config_ccd_1013 (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  if (dev->res != 0)
 | 
						|
    priv->res_step = SANE_FIX ((float) priv->hwres / (float) dev->res);
 | 
						|
 | 
						|
  set_dpi_value (dev);
 | 
						|
 | 
						|
  /* set_start_channel_1013 (dev); */
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x05);
 | 
						|
 | 
						|
  switch (dev->mode)
 | 
						|
    {
 | 
						|
    case MODE_BW:
 | 
						|
    case MODE_GRAYSCALE:
 | 
						|
      priv->channel = CCD300_CHANNEL_GRAY;
 | 
						|
      break;
 | 
						|
 | 
						|
    case MODE_COLOR:
 | 
						|
      priv->channel = CCD300_CHANNEL_RED;
 | 
						|
      break;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  set_ccd_channel_1013 (dev, priv->channel);
 | 
						|
 | 
						|
  /* set_invert_1013 (dev); */
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6,
 | 
						|
			 (dev->invert == SANE_TRUE ? 0x04 : 0x14));
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x37);
 | 
						|
  reset_bank_count (dev);
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x27);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x67);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x17);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x77);
 | 
						|
 | 
						|
  /* set_initial_skip_1013 (dev); */
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x41);
 | 
						|
 | 
						|
  priv->adjustskip = priv->skipcount + priv->skipimagebytes;
 | 
						|
 | 
						|
  DBG (5, "config_ccd_1013: adjustskip %u\n", priv->adjustskip);
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 5, priv->adjustskip / 16 + 2);
 | 
						|
 | 
						|
  priv->adjustskip %= 16;
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x81);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 5, 0x70);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x01);
 | 
						|
 | 
						|
 | 
						|
  set_line_adjust (dev);
 | 
						|
 | 
						|
  get_bank_count (dev);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/* these functions are for the 1015 chipset */
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
motor_control_1015 (Mustek_pp_Handle * dev, u_char control)
 | 
						|
{
 | 
						|
  u_char val;
 | 
						|
 | 
						|
  DBG (5, "motor_controll_1015: control code 0x%02x\n",
 | 
						|
       (unsigned int) control);
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0xF6);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x22);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 5, control);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x02);
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
 | 
						|
      sanei_pa4s2_readbegin (dev->fd, 2);
 | 
						|
      sanei_pa4s2_readbyte (dev->fd, &val);
 | 
						|
      sanei_pa4s2_readend (dev->fd);
 | 
						|
 | 
						|
    }
 | 
						|
  while ((val & 0x08) != 0);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
return_home_1015 (Mustek_pp_Handle * dev, SANE_Bool nowait)
 | 
						|
{
 | 
						|
 | 
						|
  u_char ishome, control = 0xC3;
 | 
						|
 | 
						|
  motor_control_1015 (dev, control);
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
 | 
						|
      /* check_is_home_1015 */
 | 
						|
      sanei_pa4s2_readbegin (dev->fd, 2);
 | 
						|
      sanei_pa4s2_readbyte (dev->fd, &ishome);
 | 
						|
      sanei_pa4s2_readend (dev->fd);
 | 
						|
 | 
						|
      if (nowait)
 | 
						|
	break;
 | 
						|
 | 
						|
      usleep (1000);		/* much nicer load */
 | 
						|
 | 
						|
    }
 | 
						|
  while ((ishome & 2) == 0);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
motor_forward_1015 (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  u_char control = 0x1B;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  priv->motor_step++;
 | 
						|
  set_led (dev);
 | 
						|
 | 
						|
 | 
						|
  motor_control_1015 (dev, control);
 | 
						|
 | 
						|
  set_ccd_channel_1015 (dev, priv->channel);
 | 
						|
  set_sti (dev);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
static void
 | 
						|
motor_backward_1015 (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  u_char control = 0x43;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  priv->motor_step++;
 | 
						|
 | 
						|
  set_led (dev);
 | 
						|
 | 
						|
  switch (priv->ccd_type)
 | 
						|
    {
 | 
						|
    case 1:
 | 
						|
      control = 0x1B;
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      control = 0x43;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  motor_control_1015 (dev, control);
 | 
						|
 | 
						|
  set_ccd_channel_1015 (dev, priv->channel);
 | 
						|
  set_sti (dev);
 | 
						|
 | 
						|
}
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
set_ccd_channel_1015 (Mustek_pp_Handle * dev, int channel)
 | 
						|
{
 | 
						|
 | 
						|
  u_char chancode = chan_codes_1015[channel];
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  priv->channel = channel;
 | 
						|
 | 
						|
  priv->image_control &= 0x34;
 | 
						|
  chancode |= priv->image_control;
 | 
						|
 | 
						|
 | 
						|
  priv->image_control = chancode;
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, chancode);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
config_ccd_1015 (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
 | 
						|
  u_char val;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  if (dev->res != 0)
 | 
						|
    priv->res_step = SANE_FIX ((float) priv->hwres / (float) dev->res);
 | 
						|
 | 
						|
 | 
						|
  set_dpi_value (dev);
 | 
						|
 | 
						|
  priv->image_control = 4;
 | 
						|
 | 
						|
  /* set_start_channel_1015 (dev); */
 | 
						|
 | 
						|
  switch (dev->mode)
 | 
						|
    {
 | 
						|
    case MODE_BW:
 | 
						|
    case MODE_GRAYSCALE:
 | 
						|
      priv->channel = CCD300_CHANNEL_GRAY;
 | 
						|
      break;
 | 
						|
 | 
						|
    case MODE_COLOR:
 | 
						|
      priv->channel = CCD300_CHANNEL_RED;
 | 
						|
      break;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  set_ccd_channel_1015 (dev, priv->channel);
 | 
						|
 | 
						|
 | 
						|
  /* set_invert_1015 (dev); */
 | 
						|
 | 
						|
  priv->image_control &= 0xE4;
 | 
						|
 | 
						|
  if (dev->invert == SANE_FALSE)
 | 
						|
    priv->image_control |= 0x10;
 | 
						|
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, priv->image_control);
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x23);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 5, 0x00);
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x43);
 | 
						|
 | 
						|
  switch (priv->ccd_type)
 | 
						|
    {
 | 
						|
    case 1:
 | 
						|
      val = 0x6B;
 | 
						|
      break;
 | 
						|
    case 4:
 | 
						|
      val = 0x9F;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      val = 0x92;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 5, val);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x03);
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x37);
 | 
						|
  reset_bank_count (dev);
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x27);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x67);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x17);
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x77);
 | 
						|
 | 
						|
  /* set_initial_skip_1015 (dev); */
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x41);
 | 
						|
 | 
						|
  priv->adjustskip = priv->skipcount + priv->skipimagebytes;
 | 
						|
 | 
						|
  /* if (dev->CCD.mode == MODE_COLOR)
 | 
						|
     dev->CCD.adjustskip <<= 3; */
 | 
						|
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 5, priv->adjustskip / 32 + 1);
 | 
						|
 | 
						|
  priv->adjustskip %= 32;
 | 
						|
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x81);
 | 
						|
 | 
						|
  /* expose time */
 | 
						|
  switch (priv->ccd_type)
 | 
						|
    {
 | 
						|
    case 1:
 | 
						|
 | 
						|
      val = 0xA8;
 | 
						|
      break;
 | 
						|
    case 0:
 | 
						|
      val = 0x8A;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      val = 0xA8;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 5, val);
 | 
						|
 | 
						|
  sanei_pa4s2_writebyte (dev->fd, 6, 0x01);
 | 
						|
 | 
						|
 | 
						|
  set_line_adjust (dev);
 | 
						|
 | 
						|
  get_bank_count (dev);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* these functions are interfaces only */
 | 
						|
static void
 | 
						|
config_ccd (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  DBG (5, "config_ccd: %d dpi, mode %d, invert %d, size %d\n",
 | 
						|
       priv->hwres, dev->mode, dev->invert, dev->params.pixels_per_line);
 | 
						|
 | 
						|
  switch (priv->asic)
 | 
						|
    {
 | 
						|
    case CCD300_ASIC1013:
 | 
						|
      config_ccd_1013 (dev);
 | 
						|
      break;
 | 
						|
 | 
						|
    case CCD300_ASIC1015:
 | 
						|
      config_ccd_1015 (dev);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
return_home (Mustek_pp_Handle * dev, SANE_Bool nowait)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  priv->saved_mode = dev->mode;
 | 
						|
  priv->saved_invert = dev->invert;
 | 
						|
  priv->saved_skipcount = priv->skipcount;
 | 
						|
  priv->saved_skipimagebyte = priv->skipimagebytes;
 | 
						|
  priv->saved_adjustskip = priv->adjustskip;
 | 
						|
  priv->saved_res = dev->res;
 | 
						|
  priv->saved_hwres = priv->hwres;
 | 
						|
  priv->saved_res_step = priv->res_step;
 | 
						|
  priv->saved_line_step = priv->line_step;
 | 
						|
  priv->saved_channel = priv->channel;
 | 
						|
 | 
						|
 | 
						|
  priv->hwres = dev->res = 100;
 | 
						|
  dev->mode = MODE_GRAYSCALE;
 | 
						|
 | 
						|
  priv->skipcount = priv->skipimagebytes = 0;
 | 
						|
 | 
						|
  config_ccd (dev);
 | 
						|
 | 
						|
  switch (priv->asic)
 | 
						|
    {
 | 
						|
    case CCD300_ASIC1013:
 | 
						|
      return_home_1013 (dev);
 | 
						|
      break;
 | 
						|
 | 
						|
    case CCD300_ASIC1015:
 | 
						|
      return_home_1015 (dev, nowait);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
  dev->mode = priv->saved_mode;
 | 
						|
  dev->invert = priv->saved_invert;
 | 
						|
  priv->skipcount = priv->saved_skipcount;
 | 
						|
  priv->skipimagebytes = priv->saved_skipimagebyte;
 | 
						|
  priv->adjustskip = priv->saved_adjustskip;
 | 
						|
  dev->res = priv->saved_res;
 | 
						|
  priv->hwres = priv->saved_hwres;
 | 
						|
  priv->res_step = priv->saved_res_step;
 | 
						|
  priv->line_step = priv->saved_line_step;
 | 
						|
  priv->channel = priv->saved_channel;
 | 
						|
  priv->motor_step = 0;
 | 
						|
 | 
						|
  config_ccd (dev);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
lamp (Mustek_pp_Handle * dev, int lamp_on)
 | 
						|
{
 | 
						|
 | 
						|
  set_lamp (dev, lamp_on);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
set_voltages (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  send_voltages (dev);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
move_motor (Mustek_pp_Handle * dev, int count, int forward)
 | 
						|
{
 | 
						|
 | 
						|
  int ctr;
 | 
						|
 | 
						|
  DBG (5, "move_motor: %u steps (%s)\n", count,
 | 
						|
       (forward == SANE_TRUE ? "forward" : "backward"));
 | 
						|
 | 
						|
 | 
						|
  for (ctr = 0; ctr < count; ctr++)
 | 
						|
    {
 | 
						|
 | 
						|
      move_motor_101x (dev, forward);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
calibrate (Mustek_pp_Handle * dev)
 | 
						|
{
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  DBG (5, "calibrate entered (asic = 0x%02x)\n", priv->asic);
 | 
						|
 | 
						|
  calibrate_device_101x (dev);
 | 
						|
 | 
						|
  DBG (5, "calibrate: ref_black %d, blackpos %d\n",
 | 
						|
       priv->ref_black, priv->blackpos);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
get_lineart_line (Mustek_pp_Handle * dev, SANE_Byte * buf)
 | 
						|
{
 | 
						|
  get_lineart_line_101x (dev, buf);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
get_grayscale_line (Mustek_pp_Handle * dev, SANE_Byte * buf)
 | 
						|
{
 | 
						|
 | 
						|
  get_grayscale_line_101x (dev, buf);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
get_color_line (Mustek_pp_Handle * dev, SANE_Byte * buf)
 | 
						|
{
 | 
						|
 | 
						|
  get_color_line_101x (dev, buf);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
ccd300_init (SANE_Int options, SANE_String_Const port,
 | 
						|
	     SANE_String_Const name, SANE_Attach_Callback attach)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
  unsigned char asic, ccd;
 | 
						|
  int fd;
 | 
						|
 | 
						|
  if (options != CAP_NOTHING)
 | 
						|
    {
 | 
						|
      DBG (1, "ccd300_init: called with unknown options (%#02x)\n", options);
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  /* try to attach to he supplied port */
 | 
						|
  status = sanei_pa4s2_open (port, &fd);
 | 
						|
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    {
 | 
						|
      DBG (2, "ccd300_init: couldn't attach to port ``%s'' (%s)\n",
 | 
						|
	   port, sane_strstatus (status));
 | 
						|
      return status;
 | 
						|
    }
 | 
						|
 | 
						|
  sanei_pa4s2_enable (fd, SANE_TRUE);
 | 
						|
  sanei_pa4s2_readbegin (fd, 0);
 | 
						|
  sanei_pa4s2_readbyte (fd, &asic);
 | 
						|
  sanei_pa4s2_readend (fd);
 | 
						|
  sanei_pa4s2_readbegin (fd, 2);
 | 
						|
  sanei_pa4s2_readbyte (fd, &ccd);
 | 
						|
  sanei_pa4s2_readend (fd);
 | 
						|
  sanei_pa4s2_enable (fd, SANE_FALSE);
 | 
						|
  sanei_pa4s2_close (fd);
 | 
						|
 | 
						|
  if (asic != CCD300_ASIC1013 && asic != CCD300_ASIC1015)
 | 
						|
    {
 | 
						|
      DBG (2, "ccd300_init: scanner not recognized (unknown ASIC id %#02x)\n",
 | 
						|
	   asic);
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  ccd &= (asic == CCD300_ASIC1013 ? 0x04 : 0x05);
 | 
						|
 | 
						|
  DBG (3, "ccd_init: found scanner on port ``%s'' (ASIC id %#02x, CCD %d)\n",
 | 
						|
       port, asic, ccd);
 | 
						|
 | 
						|
  return attach (port, name, MUSTEK_PP_CCD300, options);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ccd300_capabilities (SANE_Int info, SANE_String * model,
 | 
						|
		     SANE_String * vendor, SANE_String * type,
 | 
						|
		     SANE_Int * maxres, SANE_Int * minres,
 | 
						|
		     SANE_Int * maxhsize, SANE_Int * maxvsize,
 | 
						|
		     SANE_Int * caps)
 | 
						|
{
 | 
						|
  *model = strdup ("600 III EP Plus");
 | 
						|
  *vendor = strdup ("Mustek");
 | 
						|
  *type = strdup ("flatbed (CCD 300 dpi)");
 | 
						|
  DBG (3,
 | 
						|
       "ccd300_capabilities: 600 III EP Plus flatbed CCD (300 dpi) scanner\n");
 | 
						|
 | 
						|
  *maxres = 300;
 | 
						|
  *minres = 50;
 | 
						|
  *maxhsize = CCD300_MAXHSIZE;
 | 
						|
  *maxvsize = CCD300_MAXVSIZE;
 | 
						|
  *caps = info | CAP_INVERT | CAP_LAMP_OFF;
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
ccd300_open (SANE_String port, SANE_Int caps, SANE_Int * fd)
 | 
						|
{
 | 
						|
  SANE_Status status;
 | 
						|
 | 
						|
  if (caps & ~(CAP_NOTHING | CAP_INVERT | CAP_LAMP_OFF))
 | 
						|
    {
 | 
						|
      DBG (1, "ccd300_open: called with unknown capabilities (%#02x)\n",
 | 
						|
	   caps);
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  DBG (3, "ccd300_open: called for port ``%s''\n", port);
 | 
						|
 | 
						|
  status = sanei_pa4s2_open (port, fd);
 | 
						|
 | 
						|
  if (status != SANE_STATUS_GOOD)
 | 
						|
    DBG (2, "ccd300_open: open failed (%s)\n", sane_strstatus (status));
 | 
						|
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ccd300_setup (SANE_Handle handle)
 | 
						|
{
 | 
						|
  Mustek_pp_Handle *dev = handle;
 | 
						|
  mustek_pp_ccd300_priv *priv;
 | 
						|
  unsigned char asic, ccd;
 | 
						|
 | 
						|
  DBG (3, "ccd300_setup: called for port ``%s''\n", dev->dev->port);
 | 
						|
 | 
						|
  if ((priv = malloc (sizeof (mustek_pp_ccd300_priv))) == NULL)
 | 
						|
    {
 | 
						|
      DBG (1, "ccd300_setup: not enough memory\n");
 | 
						|
      return;			/* can you here the shit hitting the fan? */
 | 
						|
    }
 | 
						|
 | 
						|
  dev->priv = priv;
 | 
						|
  memset (priv, 0, sizeof (mustek_pp_ccd300_priv));
 | 
						|
 | 
						|
  priv->bw = 128;
 | 
						|
  priv->wait_bank = 700;
 | 
						|
  priv->top = 47;
 | 
						|
 | 
						|
  sanei_pa4s2_enable (dev->fd, SANE_TRUE);
 | 
						|
 | 
						|
  sanei_pa4s2_readbegin (dev->fd, 0);
 | 
						|
  sanei_pa4s2_readbyte (dev->fd, &asic);
 | 
						|
  sanei_pa4s2_readend (dev->fd);
 | 
						|
  sanei_pa4s2_readbegin (dev->fd, 2);
 | 
						|
  sanei_pa4s2_readbyte (dev->fd, &ccd);
 | 
						|
  sanei_pa4s2_readend (dev->fd);
 | 
						|
  ccd &= (asic == CCD300_ASIC1013 ? 0x04 : 0x05);
 | 
						|
  priv->asic = asic;
 | 
						|
  priv->ccd_type = ccd;
 | 
						|
 | 
						|
  return_home (dev, SANE_TRUE);
 | 
						|
  lamp (dev, SANE_TRUE);
 | 
						|
  sanei_pa4s2_enable (dev->fd, SANE_FALSE);
 | 
						|
  dev->lamp_on = time (NULL);
 | 
						|
  dev->res = priv->hwres = 300;
 | 
						|
  dev->mode = MODE_COLOR;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ccd300_close (SANE_Handle handle)
 | 
						|
{
 | 
						|
 | 
						|
  Mustek_pp_Handle *dev = handle;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  DBG (3, "ccd300_close: called for port ``%s''\n", dev->dev->port);
 | 
						|
 | 
						|
  sanei_pa4s2_enable (dev->fd, SANE_TRUE);
 | 
						|
  lamp (dev, SANE_FALSE);
 | 
						|
  return_home (dev, SANE_FALSE);
 | 
						|
  sanei_pa4s2_enable (dev->fd, SANE_FALSE);
 | 
						|
 | 
						|
  sanei_pa4s2_close (dev->fd);
 | 
						|
  free (priv);
 | 
						|
 | 
						|
  DBG (3, "ccd300_close: device shut down and all buffers freed\n");
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
ccd300_config (SANE_Handle handle, SANE_String_Const optname,
 | 
						|
	       SANE_String_Const optval)
 | 
						|
{
 | 
						|
  Mustek_pp_Handle *dev = handle;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
  int value = -1;
 | 
						|
 | 
						|
  DBG (3, "ccd300_config: called for port ``%s'' (%s%s%s)\n",
 | 
						|
       dev->dev->port,
 | 
						|
       optname, (optval ? " = " : ""), (optval ? optval : ""));
 | 
						|
 | 
						|
  if (!strcmp (optname, "bw"))
 | 
						|
    {
 | 
						|
 | 
						|
      if (!optval)
 | 
						|
	{
 | 
						|
	  DBG (1, "ccd300_config: missing value for option ``bw''\n");
 | 
						|
	  return SANE_STATUS_INVAL;
 | 
						|
	}
 | 
						|
 | 
						|
      /* ok, ok, should be strtol... know what? send me a patch. */
 | 
						|
      value = atoi (optval);
 | 
						|
 | 
						|
      if ((value < 0) || (value > 255))
 | 
						|
	{
 | 
						|
	  DBG (1,
 | 
						|
	       "ccd300_config: value ``%s'' for option ``bw'' is out of range (0 <= bw <= 255)\n",
 | 
						|
	       optval);
 | 
						|
	  return SANE_STATUS_INVAL;
 | 
						|
	}
 | 
						|
 | 
						|
      priv->bw = value;
 | 
						|
 | 
						|
    }
 | 
						|
  else if (!strcmp (optname, "waitbank"))
 | 
						|
    {
 | 
						|
 | 
						|
      if (!optval)
 | 
						|
	{
 | 
						|
	  DBG (1, "ccd300_config: missing value for option ``waitbank''\n");
 | 
						|
	  return SANE_STATUS_INVAL;
 | 
						|
	}
 | 
						|
 | 
						|
      value = atoi (optval);
 | 
						|
 | 
						|
      if (value < 0)
 | 
						|
	{
 | 
						|
	  DBG (1,
 | 
						|
	       "ccd300_config: value ``%s'' for option ``waitbank'' is out of range (>= 0)\n",
 | 
						|
	       optval);
 | 
						|
	  return SANE_STATUS_INVAL;
 | 
						|
	}
 | 
						|
 | 
						|
      priv->wait_bank = value;
 | 
						|
    }
 | 
						|
  else if (!strcmp (optname, "top"))
 | 
						|
    {
 | 
						|
 | 
						|
      if (!optval)
 | 
						|
	{
 | 
						|
	  DBG (1, "ccd300_config: missing value for option ``top''\n");
 | 
						|
	  return SANE_STATUS_INVAL;
 | 
						|
	}
 | 
						|
 | 
						|
      value = atoi (optval);
 | 
						|
 | 
						|
      if (value < 0)
 | 
						|
	{
 | 
						|
	  DBG (1,
 | 
						|
	       "ccd300_config: value ``%s'' for option ``top'' is out of range (>= 0)\n",
 | 
						|
	       optval);
 | 
						|
	  return SANE_STATUS_INVAL;
 | 
						|
	}
 | 
						|
 | 
						|
      priv->top = value;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      DBG (1, "ccd300_config: unknown option ``%s''", optname);
 | 
						|
      return SANE_STATUS_INVAL;
 | 
						|
    }
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ccd300_stop (SANE_Handle handle)
 | 
						|
{
 | 
						|
  Mustek_pp_Handle *dev = handle;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
  int cnt;
 | 
						|
 | 
						|
  DBG (3, "ccd300_stop: stopping scan operating on port ``%s''\n",
 | 
						|
       dev->dev->port);
 | 
						|
 | 
						|
  sanei_pa4s2_enable (dev->fd, SANE_TRUE);
 | 
						|
  return_home (dev, SANE_TRUE);
 | 
						|
  sanei_pa4s2_enable (dev->fd, SANE_FALSE);
 | 
						|
 | 
						|
  free (priv->calib_r);
 | 
						|
  free (priv->calib_g);
 | 
						|
  free (priv->calib_b);
 | 
						|
 | 
						|
  if (priv->red)
 | 
						|
    {
 | 
						|
      for (cnt = 0; cnt < priv->green_offs; cnt++)
 | 
						|
	free (priv->red[cnt]);
 | 
						|
      free (priv->red);
 | 
						|
    }
 | 
						|
  if (priv->blue)
 | 
						|
    {
 | 
						|
      for (cnt = 0; cnt < priv->blue_offs; cnt++)
 | 
						|
	free (priv->blue[cnt]);
 | 
						|
      free (priv->blue);
 | 
						|
    }
 | 
						|
  free (priv->green);
 | 
						|
 | 
						|
  priv->calib_r = priv->calib_g = priv->calib_b = NULL;
 | 
						|
  priv->red = priv->blue = NULL;
 | 
						|
  priv->green = NULL;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static SANE_Status
 | 
						|
ccd300_start (SANE_Handle handle)
 | 
						|
{
 | 
						|
  Mustek_pp_Handle *dev = handle;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  DBG (3, "ccd300_start: called for port ``%s''\n", dev->dev->port);
 | 
						|
 | 
						|
  if (dev->res <= 100)
 | 
						|
    priv->hwres = 100;
 | 
						|
  else if (dev->res <= 200)
 | 
						|
    priv->hwres = 200;
 | 
						|
  else if (dev->res <= 300)
 | 
						|
    priv->hwres = 300;
 | 
						|
 | 
						|
  DBG (4, "ccd300_start: setting hardware resolution to %d dpi\n",
 | 
						|
       priv->hwres);
 | 
						|
 | 
						|
  priv->skipimagebytes = dev->topX;
 | 
						|
 | 
						|
  sanei_pa4s2_enable (dev->fd, SANE_TRUE);
 | 
						|
  config_ccd (dev);
 | 
						|
  set_voltages (dev);
 | 
						|
  get_bank_count (dev);
 | 
						|
 | 
						|
  if (priv->bank_count != 0)
 | 
						|
    {
 | 
						|
      DBG (2, "ccd300_start: bank count is not zero...\n");
 | 
						|
    }
 | 
						|
 | 
						|
  return_home (dev, SANE_FALSE);
 | 
						|
 | 
						|
  priv->motor_step = 0;
 | 
						|
 | 
						|
  /* allocate memory for calibration */
 | 
						|
  if ((priv->calib_g = malloc (dev->params.pixels_per_line)) == NULL)
 | 
						|
    {
 | 
						|
      sanei_pa4s2_enable (dev->fd, SANE_FALSE);
 | 
						|
      DBG (1, "ccd300_start: not enough memory\n");
 | 
						|
      return SANE_STATUS_NO_MEM;
 | 
						|
    }
 | 
						|
 | 
						|
  if (dev->mode == MODE_COLOR)
 | 
						|
    {
 | 
						|
      priv->calib_r = malloc (dev->params.pixels_per_line);
 | 
						|
      priv->calib_b = malloc (dev->params.pixels_per_line);
 | 
						|
 | 
						|
      if ((priv->calib_r == NULL) || (priv->calib_b == NULL))
 | 
						|
	{
 | 
						|
	  free (priv->calib_g);
 | 
						|
	  free (priv->calib_r);
 | 
						|
	  free (priv->calib_b);
 | 
						|
	  priv->calib_r = priv->calib_g = priv->calib_b = NULL;
 | 
						|
 | 
						|
	  sanei_pa4s2_enable (dev->fd, SANE_FALSE);
 | 
						|
	  DBG (1, "ccd300_start: not enough memory\n");
 | 
						|
	  return SANE_STATUS_NO_MEM;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  calibrate (dev);
 | 
						|
 | 
						|
  if (priv->ccd_type == 1)
 | 
						|
    {
 | 
						|
      priv->blue_offs = 4;
 | 
						|
      priv->green_offs = 8;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      priv->blue_offs = 8;
 | 
						|
      priv->green_offs = 16;
 | 
						|
    }
 | 
						|
 | 
						|
  move_motor (dev, priv->top + dev->topY -
 | 
						|
	      (dev->mode == MODE_COLOR ? priv->green_offs : 0), SANE_TRUE);
 | 
						|
 | 
						|
  if (priv->ccd_type == 1)
 | 
						|
    sanei_pa4s2_writebyte (dev->fd, 6, 0x15);
 | 
						|
 | 
						|
  sanei_pa4s2_enable (dev->fd, SANE_FALSE);
 | 
						|
 | 
						|
  if (dev->mode == MODE_COLOR)
 | 
						|
    {
 | 
						|
      int failed = SANE_FALSE, cnt;
 | 
						|
 | 
						|
      priv->line_step = SANE_FIX (300.0 / (float) dev->res);
 | 
						|
      priv->rdiff = priv->line_step;
 | 
						|
      priv->bdiff = priv->rdiff + (priv->blue_offs << SANE_FIXED_SCALE_SHIFT);
 | 
						|
      priv->gdiff =
 | 
						|
	priv->rdiff + (priv->green_offs << SANE_FIXED_SCALE_SHIFT);
 | 
						|
 | 
						|
      priv->red = malloc (sizeof (SANE_Byte *) * priv->green_offs);
 | 
						|
      priv->blue = malloc (sizeof (SANE_Byte *) * priv->blue_offs);
 | 
						|
      priv->green = malloc (dev->params.pixels_per_line);
 | 
						|
 | 
						|
      if ((priv->red == NULL) || (priv->blue == NULL)
 | 
						|
	  || (priv->green == NULL))
 | 
						|
	{
 | 
						|
	  free (priv->calib_r);
 | 
						|
	  free (priv->calib_g);
 | 
						|
	  free (priv->calib_b);
 | 
						|
	  priv->calib_r = priv->calib_g = priv->calib_b = NULL;
 | 
						|
 | 
						|
	  free (priv->red);
 | 
						|
	  free (priv->green);
 | 
						|
	  free (priv->blue);
 | 
						|
	  priv->red = priv->blue = NULL;
 | 
						|
	  priv->green = NULL;
 | 
						|
 | 
						|
	  DBG (1, "ccd300_start: not enough memory for ld buffers\n");
 | 
						|
	  return SANE_STATUS_NO_MEM;
 | 
						|
	}
 | 
						|
 | 
						|
      /* note to myself: better allocate one huge chunk of memory and set
 | 
						|
         pointers */
 | 
						|
      for (cnt = 0; cnt < priv->green_offs; cnt++)
 | 
						|
	if ((priv->red[cnt] = malloc (dev->params.pixels_per_line)) == NULL)
 | 
						|
	  failed = SANE_TRUE;
 | 
						|
 | 
						|
      for (cnt = 0; cnt < priv->blue_offs; cnt++)
 | 
						|
	if ((priv->blue[cnt] = malloc (dev->params.pixels_per_line)) == NULL)
 | 
						|
	  failed = SANE_TRUE;
 | 
						|
 | 
						|
      if (failed == SANE_TRUE)
 | 
						|
	{
 | 
						|
	  free (priv->calib_r);
 | 
						|
	  free (priv->calib_g);
 | 
						|
	  free (priv->calib_b);
 | 
						|
	  priv->calib_r = priv->calib_g = priv->calib_b = NULL;
 | 
						|
 | 
						|
	  for (cnt = 0; cnt < priv->green_offs; cnt++)
 | 
						|
	    free (priv->red[cnt]);
 | 
						|
	  for (cnt = 0; cnt < priv->blue_offs; cnt++)
 | 
						|
	    free (priv->blue[cnt]);
 | 
						|
 | 
						|
	  free (priv->red);
 | 
						|
	  free (priv->green);
 | 
						|
	  free (priv->blue);
 | 
						|
	  priv->red = priv->blue = NULL;
 | 
						|
	  priv->green = NULL;
 | 
						|
 | 
						|
	  DBG (1, "ccd300_start: not enough memory for ld buffers\n");
 | 
						|
	  return SANE_STATUS_NO_MEM;
 | 
						|
	}
 | 
						|
 | 
						|
      priv->redline = priv->blueline = priv->ccd_line = 0;
 | 
						|
    }
 | 
						|
 | 
						|
  priv->lines = 0;
 | 
						|
  priv->lines_left = dev->params.lines;
 | 
						|
 | 
						|
  DBG (3, "ccd300_start: device ready for scanning\n");
 | 
						|
 | 
						|
  return SANE_STATUS_GOOD;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ccd300_read (SANE_Handle handle, SANE_Byte * buffer)
 | 
						|
{
 | 
						|
  Mustek_pp_Handle *dev = handle;
 | 
						|
  mustek_pp_ccd300_priv *priv = dev->priv;
 | 
						|
 | 
						|
  DBG (3, "ccd300_read: receiving one line from port ``%s''\n",
 | 
						|
       dev->dev->port);
 | 
						|
 | 
						|
  sanei_pa4s2_enable (dev->fd, SANE_TRUE);
 | 
						|
 | 
						|
  switch (dev->mode)
 | 
						|
    {
 | 
						|
    case MODE_BW:
 | 
						|
      get_lineart_line (dev, buffer);
 | 
						|
      break;
 | 
						|
 | 
						|
    case MODE_GRAYSCALE:
 | 
						|
      get_grayscale_line (dev, buffer);
 | 
						|
      break;
 | 
						|
 | 
						|
    case MODE_COLOR:
 | 
						|
      get_color_line (dev, buffer);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  priv->lines_left--;
 | 
						|
  priv->lines++;
 | 
						|
 | 
						|
  DBG (4, "ccd300_read: %d lines read (%d to go)\n", priv->lines,
 | 
						|
       priv->lines_left);
 | 
						|
 | 
						|
  if (priv->lines_left == 0)
 | 
						|
    {
 | 
						|
      DBG (3, "ccd300_read: scan finished\n");
 | 
						|
      return_home (dev, SANE_TRUE);
 | 
						|
    }
 | 
						|
 | 
						|
  sanei_pa4s2_enable (dev->fd, SANE_FALSE);
 | 
						|
 | 
						|
}
 |