Logo Search packages:      
Sourcecode: sane-backends version File versions

canon-sane.c

SANE_Status
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
{
  char devnam[PATH_MAX] = "/dev/scanner";
  FILE *fp;

  int i, j;
  SANE_Byte primary, secondary, inmask, priMask, secMask;

  DBG_INIT ();
  DBG (1, ">> sane_init\n");

/****** for lineart mode of FB1200S ******/
  for (i = 0; i < 256; i++)
    {
      primary = secondary = 0;
      inmask = 0x80;
      priMask = 0x40;
      secMask = 0x80;
      for (j = 0; j < 4; j++)
        {
          if (i & inmask)
            {
              primary |= priMask;
            secondary |= secMask;
          }
        priMask = priMask >> 2;
        secMask = secMask >> 2;
        inmask  = inmask >> 1;
      }
      primaryHigh[i] = primary;
      secondaryHigh[i] = secondary;

      primary = secondary = 0;
      priMask = 0x40;
      secMask = 0x80;
      for (j = 0; j < 4; j++)
      {
        if (i & inmask)
          {
            primary |= priMask;
            secondary |= secMask;
          }
        priMask = priMask >> 2;
        secMask = secMask >> 2;
        inmask  = inmask >> 1;
      }
      primaryLow[i] = primary;
      secondaryLow[i] = secondary;
    }
/******************************************/

#if defined PACKAGE && defined VERSION
  DBG (2, "sane_init: " PACKAGE " " VERSION "\n");
#endif

  if (version_code)
    *version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 0);

  fp = sanei_config_open (CANON_CONFIG_FILE);
  if (fp)
    {
      char line[PATH_MAX];
      size_t len;

      /* read config file */
      /* while (fgets (line, sizeof (line), fp)) */
      while (sanei_config_read (line, sizeof (line), fp))
      {
        if (line[0] == '#')   /* ignore line comments */
          continue;
        len = strlen (line);
        /*if (line[len - 1] == '\n')
           line[--len] = '\0'; */

        if (!len)
          continue;           /* ignore empty lines */
        strcpy (devnam, line);
      }
      fclose (fp);
    }
  sanei_config_attach_matching_devices (devnam, attach_one);
  DBG (1, "<< sane_init\n");
  return SANE_STATUS_GOOD;
}

/**************************************************************************/

void
sane_exit (void)
{
  CANON_Device *dev, *next;
  DBG (1, ">> sane_exit\n");

  for (dev = first_dev; dev; dev = next)
    {
      next = dev->next;
      free ((void *) dev->sane.name);
      free ((void *) dev->sane.model);
      free (dev);
    }

  DBG (1, "<< sane_exit\n");
}

/**************************************************************************/

SANE_Status
sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
{
  static const SANE_Device **devlist = 0;
  CANON_Device *dev;
  int i;
  DBG (1, ">> sane_get_devices\n");

  if (devlist)
    free (devlist);
  devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
  if (!devlist)
    return (SANE_STATUS_NO_MEM);

  i = 0;
  for (dev = first_dev; dev; dev = dev->next)
    devlist[i++] = &dev->sane;
  devlist[i++] = 0;

  *device_list = devlist;

  DBG (1, "<< sane_get_devices\n");
  return SANE_STATUS_GOOD;
}

/**************************************************************************/

SANE_Status
sane_open (SANE_String_Const devnam, SANE_Handle * handle)
{
  SANE_Status status;
  CANON_Device *dev;
  CANON_Scanner *s;
  int i, j, c;

  DBG (1, ">> sane_open\n");

  if (devnam[0] == '\0')
    {
      for (dev = first_dev; dev; dev = dev->next)
      {
        if (strcmp (dev->sane.name, devnam) == 0)
          break;
      }
    }
  else
    {
      dev = first_dev;
    }

  if (!dev)
    {
      status = attach (devnam, &dev);
      if (status != SANE_STATUS_GOOD)
      return (status);
    }


  if (!dev)
    return (SANE_STATUS_INVAL);

  s = malloc (sizeof (*s));
  if (!s)
    return SANE_STATUS_NO_MEM;
  memset (s, 0, sizeof (*s));

  s->fd = -1;
  s->hw = dev;

  if (s->hw->info.model == FS2710)
    {
      for (i = 0; i < 4; i++)
      {
        s->gamma_map[i][0] = '\0';
        s->gamma_table[i][0] = 0;
      }
      for (j = 1; j < 4096; ++j)
      {                 /* FS2710 needs inital gamma 2.0 */
        c = (int) (256.0 * pow (((double) j) / 4096.0, 0.5));
        for (i = 0; i < 4; i++)
          {
            s->gamma_map[i][j] = (u_char) c;
            if ((j & 0xf) == 0)
            s->gamma_table[i][j >> 4] = c;
          }
      }
      s->colour = 1;
      s->auxbuf_len = 0;
    }
  else
    {
      for (i = 0; i < 4; ++i)
      {
        for (j = 0; j < 256; ++j)
          s->gamma_table[i][j] = j;
      }
    }

  init_options (s);

  if (s->hw->info.model == FB1200)
    s->inbuffer = malloc (30894);   /* modification for FB1200S */
  else
    s->inbuffer = malloc (15312);   /* modification for FB620S */

  if (!s->inbuffer)
    return SANE_STATUS_NO_MEM;

  if (s->hw->info.model == FB1200)
    s->outbuffer = malloc (30894);  /* modification for FB1200S */
  else
    s->outbuffer = malloc (15312);  /* modification for FB620S */

  if (!s->outbuffer)
    {
      free (s->inbuffer);
      return SANE_STATUS_NO_MEM;
    }

  s->next = first_handle;
  first_handle = s;

  *handle = s;

  DBG (1, "<< sane_open\n");
  return SANE_STATUS_GOOD;

}

/**************************************************************************/

void
sane_close (SANE_Handle handle)
{
  CANON_Scanner *s = (CANON_Scanner *) handle;
  SANE_Status status;

  DBG (1, ">> sane_close\n");

  if (s->val[OPT_EJECT_BEFOREEXIT].w == SANE_TRUE)
    {
      if (s->fd == -1)
      {
        sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, s->hw);
      }
      status = medium_position (s->fd);
      if (status != SANE_STATUS_GOOD)
      {
        DBG (1, "sane_close: MEDIUM POSITION failed\n");
        sanei_scsi_close (s->fd);
        s->fd = -1;
      }
      s->AF_NOW = SANE_TRUE;
      DBG (1, "sane_close AF_NOW = '%d'\n", s->AF_NOW);
    }

  if (s->fd != -1)
    {
      sanei_scsi_close (s->fd);
    }

  if (s->inbuffer)
    free (s->inbuffer);       /* modification for FB620S */
  if (s->outbuffer)
    free (s->outbuffer);      /* modification for FB620S */
  if (s->auxbuf_len > 0)
    free (s->auxbuf);         /* modification for FS2710S */

  free (s);

  DBG (1, ">> sane_close\n");
}

/**************************************************************************/

const SANE_Option_Descriptor *
sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
{
  CANON_Scanner *s = handle;
  DBG (21, ">> sane_get_option_descriptor option number %d\n", option);

  if ((unsigned) option >= NUM_OPTIONS)
    return (0);

  DBG (21, "   sane_get_option_descriptor option name %s\n",
       option_name[option]);

  DBG (21, "<< sane_get_option_descriptor option number %d\n", option);
  return (s->opt + option);
}

/**************************************************************************/
SANE_Status
sane_control_option (SANE_Handle handle, SANE_Int option,
                 SANE_Action action, void *val, SANE_Int * info)
{
  CANON_Scanner *s = handle;
  SANE_Status status;
  SANE_Word w, cap;
  SANE_Byte gbuf[4096];
  size_t buf_size;
  int i, neg, gamma_component, int_t, transfer_data_type;
  time_t dtime, rt;

  DBG (21, ">> sane_control_option %s\n", option_name[option]);

  if (info)
    *info = 0;

  if (s->scanning == SANE_TRUE)
    {
      DBG (21, ">> sane_control_option: device is busy scanning\n");
      return (SANE_STATUS_DEVICE_BUSY);
    }
  if (option >= NUM_OPTIONS)
    return (SANE_STATUS_INVAL);

  cap = s->opt[option].cap;
  if (!SANE_OPTION_IS_ACTIVE (cap))
    return (SANE_STATUS_INVAL);

  if (action == SANE_ACTION_GET_VALUE)
    {
      DBG (21, "sane_control_option get value of %s\n", option_name[option]);
      switch (option)
      {
        /* word options: */
      case OPT_FLATBED_ONLY:
      case OPT_TPU_ON:
      case OPT_TPU_PN:
      case OPT_TPU_TRANSPARENCY:
      case OPT_RESOLUTION_BIND:
      case OPT_HW_RESOLUTION_ONLY:  /* 990320, ss */
      case OPT_X_RESOLUTION:
      case OPT_Y_RESOLUTION:
      case OPT_TL_X:
      case OPT_TL_Y:
      case OPT_BR_X:
      case OPT_BR_Y:
      case OPT_NUM_OPTS:
      case OPT_BRIGHTNESS:
      case OPT_CONTRAST:
      case OPT_CUSTOM_GAMMA:
      case OPT_CUSTOM_GAMMA_BIND:
      case OPT_HNEGATIVE:
        /*     case OPT_GRC: */
      case OPT_MIRROR:
      case OPT_AE:
      case OPT_PREVIEW:
      case OPT_BIND_HILO:
      case OPT_HILITE_R:
      case OPT_SHADOW_R:
      case OPT_HILITE_G:
      case OPT_SHADOW_G:
      case OPT_HILITE_B:
      case OPT_SHADOW_B:
      case OPT_EJECT_AFTERSCAN:
      case OPT_EJECT_BEFOREEXIT:
      case OPT_THRESHOLD:
      case OPT_AF:
      case OPT_AF_ONCE:
      case OPT_FOCUS:
        if ((option >= OPT_NEGATIVE) && (option <= OPT_SHADOW_B))
          {
            DBG (21, "GET_VALUE for %s: s->val[%s].w = %d\n",
               option_name[option], option_name[option],
               s->val[option].w);
          }
        *(SANE_Word *) val = s->val[option].w;
        DBG (21, "value for option %s: %d\n", option_name[option],
             s->val[option].w);
        if (info)
          *info |= SANE_INFO_RELOAD_PARAMS;
        return (SANE_STATUS_GOOD);

      case OPT_GAMMA_VECTOR:
      case OPT_GAMMA_VECTOR_R:
      case OPT_GAMMA_VECTOR_G:
      case OPT_GAMMA_VECTOR_B:

        memset (gbuf, 0, sizeof (gbuf));
        buf_size = 256;
        transfer_data_type = 0x03;

        DBG (21, "sending GET_DENSITY_CURVE\n");
        if (s->val[OPT_CUSTOM_GAMMA_BIND].w == SANE_TRUE)
          /* If using bind analog gamma, option will be OPT_GAMMA_VECTOR.
             In this case, use the curve for green                        */
          gamma_component = 2;
        else
          /* Else use a different index for each curve */
          gamma_component = option - OPT_GAMMA_VECTOR;

        /* Now get the values from the scanner */
        if (s->hw->info.model != FS2710)
          {
            sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, s->hw);
            status =
            get_density_curve (s->fd, gamma_component, gbuf, &buf_size,
                           transfer_data_type);
            sanei_scsi_close (s->fd);
            s->fd = -1;
            if (status != SANE_STATUS_GOOD)
            {
              DBG (21, "GET_DENSITY_CURVE\n");
              return (SANE_STATUS_INVAL);
            }
          }
        else
          status =
            get_density_curve_fs2710 (s, gamma_component, gbuf, &buf_size);

        neg = (s->hw->info.is_filmscanner) ?
          strcmp (filmtype_list[1], s->val[OPT_NEGATIVE].s) :
          s->val[OPT_HNEGATIVE].w;

        for (i = 0; i < 256; i++)
          {
            if (neg == SANE_FALSE)
            s->gamma_table[option - OPT_GAMMA_VECTOR][i] =
              (SANE_Int) gbuf[i];
            else
            s->gamma_table[option - OPT_GAMMA_VECTOR][i] =
              255 - (SANE_Int) gbuf[255 - i];
          }

        memcpy (val, s->val[option].wa, s->opt[option].size);
        DBG (21, "value for option %s: %d\n", option_name[option],
             s->val[option].w);
        return (SANE_STATUS_GOOD);

        /* string options: */
      case OPT_TPU_DCM:
      case OPT_TPU_FILMTYPE:
      case OPT_MODE:
        strcpy (val, s->val[option].s);
        if (info)
          *info |= SANE_INFO_RELOAD_PARAMS;
        DBG (21, "value for option %s: %s\n", option_name[option],
             s->val[option].s);
        return (SANE_STATUS_GOOD);

      case OPT_NEGATIVE:
        strcpy (val, s->val[option].s);
        if (info)
          *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
        DBG (21, "value for option %s: %s\n", option_name[option],
             s->val[option].s);
        return (SANE_STATUS_GOOD);

      case OPT_NEGATIVE_TYPE:
        strcpy (val, s->val[option].s);
        if (info)
          *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
        DBG (21, "value for option %s: %s\n", option_name[option],
             s->val[option].s);
        return (SANE_STATUS_GOOD);

      case OPT_SCANNING_SPEED:
        strcpy (val, s->val[option].s);
        if (info)
          *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
        DBG (21, "value for option %s: %s\n", option_name[option],
             s->val[option].s);
        return (SANE_STATUS_GOOD);

      default:
        val = 0;
        return (SANE_STATUS_GOOD);
      }
    }
  else if (action == SANE_ACTION_SET_VALUE)
    {
      DBG (21, "sane_control_option set value for %s\n", option_name[option]);
      if (!SANE_OPTION_IS_SETTABLE (cap))
      return (SANE_STATUS_INVAL);

      status = sanei_constrain_value (s->opt + option, val, info);

      if (status != SANE_STATUS_GOOD)
      return status;

      switch (option)
      {
        /* (mostly) side-effect-free word options: */
      case OPT_TPU_PN:
      case OPT_TPU_TRANSPARENCY:
      case OPT_X_RESOLUTION:
      case OPT_Y_RESOLUTION:
      case OPT_TL_X:
      case OPT_TL_Y:
      case OPT_BR_X:
      case OPT_BR_Y:
        if (info && s->val[option].w != *(SANE_Word *) val)
          *info |= SANE_INFO_RELOAD_PARAMS;
        /* fall through */
      case OPT_NUM_OPTS:
      case OPT_BRIGHTNESS:
      case OPT_CONTRAST:
      case OPT_THRESHOLD:
      case OPT_HNEGATIVE:
        /*     case OPT_GRC: */
      case OPT_MIRROR:
      case OPT_AE:
      case OPT_PREVIEW:
      case OPT_HILITE_R:
      case OPT_SHADOW_R:
      case OPT_HILITE_G:
      case OPT_SHADOW_G:
      case OPT_HILITE_B:
      case OPT_SHADOW_B:
      case OPT_AF_ONCE:
      case OPT_FOCUS:
      case OPT_EJECT_AFTERSCAN:
      case OPT_EJECT_BEFOREEXIT:
        s->val[option].w = *(SANE_Word *) val;
        DBG (21, "SET_VALUE for %s: s->val[%s].w = %d\n",
             option_name[option], option_name[option], s->val[option].w);
        return (SANE_STATUS_GOOD);

      case OPT_RESOLUTION_BIND:
        if (s->val[option].w != *(SANE_Word *) val)
          {
            s->val[option].w = *(SANE_Word *) val;

            if (info)
            {
              *info |= SANE_INFO_RELOAD_OPTIONS;
            }
            if (s->val[option].w == SANE_FALSE)
            {           /* don't bind */
              s->opt[OPT_Y_RESOLUTION].cap &= ~SANE_CAP_INACTIVE;
              s->opt[OPT_X_RESOLUTION].title =
                SANE_TITLE_SCAN_X_RESOLUTION;
              s->opt[OPT_X_RESOLUTION].name = SANE_NAME_SCAN_X_RESOLUTION;
              s->opt[OPT_X_RESOLUTION].desc = SANE_DESC_SCAN_X_RESOLUTION;
            }
            else
            {           /* bind */
              s->opt[OPT_Y_RESOLUTION].cap |= SANE_CAP_INACTIVE;
              s->opt[OPT_X_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
              s->opt[OPT_X_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
              s->opt[OPT_X_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
            }
          }
        return SANE_STATUS_GOOD;

        /* 990320, ss: switch between slider and option menue for resolution */
      case OPT_HW_RESOLUTION_ONLY:
        if (s->val[option].w != *(SANE_Word *) val)
          {
            int iPos, xres, yres;

            s->val[option].w = *(SANE_Word *) val;

            if (info)
            {
              *info |= SANE_INFO_RELOAD_OPTIONS;
            }
            if (s->val[option].w == SANE_FALSE)
            {
              /* use complete range */
              s->opt[OPT_X_RESOLUTION].constraint_type =
                SANE_CONSTRAINT_RANGE;
              s->opt[OPT_X_RESOLUTION].constraint.range =
                &s->hw->info.xres_range;
              s->opt[OPT_Y_RESOLUTION].constraint_type =
                SANE_CONSTRAINT_RANGE;
              s->opt[OPT_Y_RESOLUTION].constraint.range =
                &s->hw->info.yres_range;
            }
            else
            {
              /* use only hardware resolutions */
              s->opt[OPT_X_RESOLUTION].constraint_type =
                SANE_CONSTRAINT_WORD_LIST;
              s->opt[OPT_X_RESOLUTION].constraint.word_list =
                s->xres_word_list;
              s->opt[OPT_Y_RESOLUTION].constraint_type =
                SANE_CONSTRAINT_WORD_LIST;
              s->opt[OPT_Y_RESOLUTION].constraint.word_list =
                s->yres_word_list;

              /* adjust resolutions */
              xres = s->xres_word_list[1];
              for (iPos = 0; iPos < s->xres_word_list[0]; iPos++)
                {
                  if (s->val[OPT_X_RESOLUTION].w >=
                    s->xres_word_list[iPos + 1])
                  {
                    xres = s->xres_word_list[iPos + 1];
                  }
                }
              s->val[OPT_X_RESOLUTION].w = xres;

              yres = s->yres_word_list[1];
              for (iPos = 0; iPos < s->yres_word_list[0]; iPos++)
                {
                  if (s->val[OPT_Y_RESOLUTION].w >=
                    s->yres_word_list[iPos + 1])
                  {
                    yres = s->yres_word_list[iPos + 1];
                  }
                }
              s->val[OPT_Y_RESOLUTION].w = yres;
            }
          }
        return (SANE_STATUS_GOOD);

      case OPT_BIND_HILO:
        if (s->val[option].w != *(SANE_Word *) val)
          {
            s->val[option].w = *(SANE_Word *) val;

            if (info)
            {
              *info |= SANE_INFO_RELOAD_OPTIONS;
            }
            if (s->val[option].w == SANE_FALSE)
            {           /* don't bind */
              s->opt[OPT_HILITE_R].cap &= ~SANE_CAP_INACTIVE;
              s->opt[OPT_SHADOW_R].cap &= ~SANE_CAP_INACTIVE;
              s->opt[OPT_HILITE_B].cap &= ~SANE_CAP_INACTIVE;
              s->opt[OPT_SHADOW_B].cap &= ~SANE_CAP_INACTIVE;

              s->opt[OPT_HILITE_G].title = SANE_TITLE_HIGHLIGHT_G;
              s->opt[OPT_HILITE_G].name = SANE_NAME_HIGHLIGHT_G;
              s->opt[OPT_HILITE_G].desc = SANE_DESC_HIGHLIGHT_G;

              s->opt[OPT_SHADOW_G].title = SANE_TITLE_SHADOW_G;
              s->opt[OPT_SHADOW_G].name = SANE_NAME_SHADOW_G;
              s->opt[OPT_SHADOW_G].desc = SANE_DESC_SHADOW_G;
            }
            else
            {           /* bind */
              s->opt[OPT_HILITE_R].cap |= SANE_CAP_INACTIVE;
              s->opt[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
              s->opt[OPT_HILITE_B].cap |= SANE_CAP_INACTIVE;
              s->opt[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;

              s->opt[OPT_HILITE_G].title = SANE_TITLE_HIGHLIGHT;
              s->opt[OPT_HILITE_G].name = SANE_NAME_HIGHLIGHT;
              s->opt[OPT_HILITE_G].desc = SANE_DESC_HIGHLIGHT;

              s->opt[OPT_SHADOW_G].title = SANE_TITLE_SHADOW;
              s->opt[OPT_SHADOW_G].name = SANE_NAME_SHADOW;
              s->opt[OPT_SHADOW_G].desc = SANE_DESC_SHADOW;
            }
          }
        return SANE_STATUS_GOOD;

      case OPT_AF:
        if (info && s->val[option].w != *(SANE_Word *) val)
          *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
        s->val[option].w = *(SANE_Word *) val;
        w = *(SANE_Word *) val;
        if (w)
          {
            s->opt[OPT_AF_ONCE].cap &= ~SANE_CAP_INACTIVE;
            s->opt[OPT_FOCUS].cap |= SANE_CAP_INACTIVE;
          }
        else
          {
            s->opt[OPT_AF_ONCE].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_FOCUS].cap &= ~SANE_CAP_INACTIVE;
          }
        return (SANE_STATUS_GOOD);

      case OPT_FLATBED_ONLY:
        switch (action)
          {
          case SANE_ACTION_SET_VALUE:
            s->val[option].w = *(SANE_Word *) val;
            if (s->hw->adf.Status != ADF_STAT_NONE && s->val[option].w == SANE_TRUE)      /* switch on */
            {
              s->hw->adf.Priority |= 0x03;      /* flatbed mode */
              s->hw->adf.Feeder &= 0x00;  /* no autofeed mode (default) */
              s->hw->adf.Status = ADF_STAT_DISABLED;
              s->val[option].w = SANE_TRUE;
            }           /* if it isn't connected, don't bother fixing */
            break;
          case SANE_ACTION_GET_VALUE:
            val = &s->val[option].w;
            break;
          default:
            break;
          }
        return SANE_STATUS_GOOD;

      case OPT_TPU_ON:
        if (s->val[OPT_TPU_ON].w == TPU_STAT_INACTIVE)      /* switch on */
          {
            s->val[OPT_TPU_ON].w = TPU_STAT_ACTIVE;
            s->opt[OPT_TPU_ON].title = "Turn Off the Transparency Unit";
            s->opt[OPT_TPU_TRANSPARENCY].cap &=
            (s->hw->tpu.ControlMode == 3) ? ~SANE_CAP_INACTIVE : ~0;
            s->opt[OPT_TPU_FILMTYPE].cap &=
            (s->hw->tpu.ControlMode == 1) ? ~SANE_CAP_INACTIVE : ~0;
          }
        else                  /* switch off */
          {
            s->val[OPT_TPU_ON].w = TPU_STAT_INACTIVE;
            s->opt[OPT_TPU_ON].title = "Turn On Transparency Unit";
            s->opt[OPT_TPU_TRANSPARENCY].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_TPU_FILMTYPE].cap |= SANE_CAP_INACTIVE;
          }
        s->opt[OPT_TPU_PN].cap ^= SANE_CAP_INACTIVE;
        s->opt[OPT_TPU_DCM].cap ^= SANE_CAP_INACTIVE;
          if (info)
        *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
        return SANE_STATUS_GOOD;

      case OPT_TPU_DCM:
        if (s->val[OPT_TPU_DCM].s)
          free (s->val[OPT_TPU_DCM].s);
        s->val[OPT_TPU_DCM].s = strdup (val);

        s->opt[OPT_TPU_TRANSPARENCY].cap |= SANE_CAP_INACTIVE;
        s->opt[OPT_TPU_FILMTYPE].cap |= SANE_CAP_INACTIVE;
        if (!strcmp (s->val[OPT_TPU_DCM].s,
                   "Correction according to Transparency Ratio"))
          {
            s->hw->tpu.ControlMode = 3;
            s->opt[OPT_TPU_TRANSPARENCY].cap &= ~SANE_CAP_INACTIVE;
          }
        else if (!strcmp (s->val[OPT_TPU_DCM].s,
                      "Correction according to Film type"))
          {
            s->hw->tpu.ControlMode = 1;
            s->opt[OPT_TPU_FILMTYPE].cap &= ~SANE_CAP_INACTIVE;
          }
        else
          s->hw->tpu.ControlMode = 0;
          if (info)
        *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
        return SANE_STATUS_GOOD;

      case OPT_TPU_FILMTYPE:
        if (s->val[option].s)
          free (s->val[option].s);
        s->val[option].s = strdup (val);
        return SANE_STATUS_GOOD;

      case OPT_MODE:
        if (info && strcmp (s->val[option].s, (SANE_String) val))
          *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
        if (s->val[option].s)
          free (s->val[option].s);
        s->val[option].s = strdup (val);
        if (!strcmp (val, "Lineart") || !strcmp (val, "Halftone"))
          {
            /* For Lineart and Halftone: */
            /* Enable "threshold" */
            s->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;

            /* Disable "custom gamma" and "brightness & contrast" */
            s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_CUSTOM_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;

            s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
          }
        else
          {
            /* For Gray and Color modes: */
            /* Disable "threshold" */
            s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;

            /* Enable "custom gamma" and "brightness & contrast" */
            s->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
            if (s->val[OPT_CUSTOM_GAMMA].w == SANE_TRUE)
            {
              if (!strcmp (val, "Color") || !strcmp (val, "Fine color"))
                {
                  s->opt[OPT_CUSTOM_GAMMA_BIND].cap &= ~SANE_CAP_INACTIVE;
                  if (s->val[OPT_CUSTOM_GAMMA_BIND].w == SANE_TRUE)
                  {
                    s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
                    s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
                    s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
                    s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
                  }
                  else
                  {
                    s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
                    s->opt[OPT_GAMMA_VECTOR_R].cap &=
                      ~SANE_CAP_INACTIVE;
                    s->opt[OPT_GAMMA_VECTOR_G].cap &=
                      ~SANE_CAP_INACTIVE;
                    s->opt[OPT_GAMMA_VECTOR_B].cap &=
                      ~SANE_CAP_INACTIVE;
                  }
                }
              else
                {
                  s->opt[OPT_CUSTOM_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
                  s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
                  s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
                  s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
                  s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
                }
            }
            else
            {
              s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
              s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
            }
          }
        return (SANE_STATUS_GOOD);

      case OPT_NEGATIVE:
        if (info && strcmp (s->val[option].s, (SANE_String) val))
          *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
        if (s->val[option].s)
          free (s->val[option].s);
        s->val[option].s = strdup (val);
        if (!strcmp (val, "Negatives"))
          {
            s->RIF = 0;
            s->opt[OPT_NEGATIVE_TYPE].cap &= ~SANE_CAP_INACTIVE;
            if (SANE_OPTION_IS_SETTABLE(s->opt[OPT_SCANNING_SPEED].cap))
            s->opt[OPT_SCANNING_SPEED].cap &= ~SANE_CAP_INACTIVE;
            s->opt[OPT_AE].cap |= SANE_CAP_INACTIVE;
          }
        else
          {
            s->RIF = 1;
            s->opt[OPT_NEGATIVE_TYPE].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_SCANNING_SPEED].cap |= SANE_CAP_INACTIVE;
            if (s->hw->info.can_autoexpose)
            s->opt[OPT_AE].cap &= ~SANE_CAP_INACTIVE;
          }
        return (SANE_STATUS_GOOD);

      case OPT_NEGATIVE_TYPE:
        if (info && strcmp (s->val[option].s, (SANE_String) val))
          *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
        if (s->val[option].s)
          free (s->val[option].s);
        s->val[option].s = strdup (val);
        for (i = 0; strcmp (val, negative_filmtype_list[i]); i++);
        s->negative_filmtype = i;
        return (SANE_STATUS_GOOD);

      case OPT_SCANNING_SPEED:
        if (info && strcmp (s->val[option].s, (SANE_String) val))
          *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
        if (s->val[option].s)
          free (s->val[option].s);
        s->val[option].s = strdup (val);
        for (i = 0; strcmp (val, scanning_speed_list[i]); i++);
        s->scanning_speed = i;
        return (SANE_STATUS_GOOD);

        /* modification for FB620S */
      case OPT_CALIBRATION_NOW:
        sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, s->hw);
        if (status == SANE_STATUS_GOOD)
          {
            status = execute_calibration (s->fd);
            if (status != SANE_STATUS_GOOD)
            {
              DBG (21, "EXECUTE CALIBRATION failed\n");
              sanei_scsi_close (s->fd);
              s->fd = -1;
              return (SANE_STATUS_INVAL);
            }
            DBG (21, "EXECUTE CALIBRATION\n");
            sanei_scsi_close (s->fd);
          }
        else
          {
            DBG (1, "calibration: cannot open device file\n");
          }
        s->fd = -1;
        return status;

      case OPT_SCANNER_SELF_DIAGNOSTIC:
        sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, s->hw);
        if (status == SANE_STATUS_GOOD)
          {
            status = send_diagnostic (s->fd);
            {
            if (status != SANE_STATUS_GOOD)
              {
                DBG (21, "SEND DIAGNOSTIC error: %s\n",
                   sane_strstatus (status));
                sanei_scsi_close (s->fd);
                s->fd = -1;
                return (status);
              }
            DBG (21, "SEND DIAGNOSTIC result: %s\n",
                 sane_strstatus (status));
            sanei_scsi_close (s->fd);
            }
          }
        else
          {
            DBG (1, "send diagnostic: cannot open device file\n");
          }
        s->fd = -1;
        return status;

      case OPT_RESET_SCANNER:
        sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, s->hw);
        if (status == SANE_STATUS_GOOD)
          {
            time (&(s->time1));
            DBG (11, "time0 = %ld\n", (u_long) s->time0);
            DBG (11, "time1 = %ld\n", (u_long) s->time1);
            dtime = (s->time1) - (s->time0);
            DBG (11, "dtime = %ld\n", (u_long) dtime);

            DBG (11, "switch_preview = %d\n", s->switch_preview);
            if (s->switch_preview == 0)
            {
              rt =
                sqrt (15 * 15 * (SANE_UNFIX (s->val[OPT_BR_Y].w)) / 297) +
                0.5;
              rt = rt + 2;
            }
            else
            rt = 17;

            DBG (11, "SANE_UNFIX(s->val[OPT_BR_Y].w) = %f\n",
               SANE_UNFIX (s->val[OPT_BR_Y].w));
            DBG (11, "rt = %ld\n", (u_long) rt);

            if (dtime < rt)
            {
              int_t = (int) (rt - dtime);
              DBG (11, "int_t = %d\n", int_t);

              sleep (int_t);
            }
            status = reset_scanner (s->fd);
            {
            if (status != SANE_STATUS_GOOD)
              {
                DBG (21, "RESET SCANNER failed\n");
                sanei_scsi_close (s->fd);
                s->fd = -1;
                return (status);
              }

            DBG (21, "RESET SCANNER\n");
            sanei_scsi_close (s->fd);
            }
          }
        else
          {
            DBG (1, "reset scanner: cannot open device file\n");
          }
        s->fd = -1;
        return status;

      case OPT_EJECT_NOW:
        sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, s->hw);
        status = medium_position (s->fd);
        if (status != SANE_STATUS_GOOD)
          {
            DBG (21, "MEDIUM POSITION failed\n");
            sanei_scsi_close (s->fd);
            s->fd = -1;
            return (SANE_STATUS_INVAL);
          }
        DBG (21, "AF_NOW before = '%d'\n", s->AF_NOW);
        s->AF_NOW = SANE_TRUE;
        DBG (21, "AF_NOW after = '%d'\n", s->AF_NOW);
        sanei_scsi_close (s->fd);
        s->fd = -1;
        return status;

      case OPT_CUSTOM_GAMMA:
        w = *(SANE_Word *) val;

        if (w == s->val[OPT_CUSTOM_GAMMA].w)
          return SANE_STATUS_GOOD;  /* no change */

        if (info)
          *info |= SANE_INFO_RELOAD_OPTIONS;

        s->val[OPT_CUSTOM_GAMMA].w = w;
        if (w)
          {
            const char *mode = s->val[OPT_MODE].s;

            if (!strcmp (mode, "Gray"))
            s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
            else if (!strcmp (mode, "Color")
                   || !strcmp (mode, "Fine color"))
            {
              s->opt[OPT_CUSTOM_GAMMA_BIND].cap &= ~SANE_CAP_INACTIVE;
              if (s->val[OPT_CUSTOM_GAMMA_BIND].w == SANE_TRUE)
                {
                  s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
                  s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
                  s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
                  s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
                }
              else
                {
                  s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
                  s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
                  s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
                  s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
                }
            }
            s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
          }
        else
          {
            s->opt[OPT_CUSTOM_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;

            s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
            s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
          }

        return SANE_STATUS_GOOD;

      case OPT_CUSTOM_GAMMA_BIND:
        w = *(SANE_Word *) val;

        if (w == s->val[OPT_CUSTOM_GAMMA_BIND].w)
          return SANE_STATUS_GOOD;  /* no change */

        if (info)
          *info |= SANE_INFO_RELOAD_OPTIONS;

        s->val[OPT_CUSTOM_GAMMA_BIND].w = w;
        if (w)
          {
            s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
          }
        else
          {
            s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
            s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
          }

        return SANE_STATUS_GOOD;

      case OPT_GAMMA_VECTOR:
      case OPT_GAMMA_VECTOR_R:
      case OPT_GAMMA_VECTOR_G:
      case OPT_GAMMA_VECTOR_B:
        memcpy (s->val[option].wa, val, s->opt[option].size);
        DBG (21, "setting gamma vector\n");
/*       if (info) */
/*    *info |= SANE_INFO_RELOAD_OPTIONS; */
        return (SANE_STATUS_GOOD);

      }
    }

  DBG (1, "<< sane_control_option %s\n", option_name[option]);
  return (SANE_STATUS_INVAL);

}

/**************************************************************************/

SANE_Status
sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
{
  CANON_Scanner *s = handle;
  DBG (1, ">> sane_get_parameters\n");

  if (!s->scanning)
    {
      int width, length, xres, yres;
      const char *mode;

      memset (&s->params, 0, sizeof (s->params));

      width = SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w)
      * s->hw->info.mud / MM_PER_INCH;
      length = SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w)
      * s->hw->info.mud / MM_PER_INCH;

      xres = s->val[OPT_X_RESOLUTION].w;
      yres = s->val[OPT_Y_RESOLUTION].w;
      if ((s->val[OPT_RESOLUTION_BIND].w == SANE_TRUE)
        || (s->val[OPT_PREVIEW].w == SANE_TRUE))
      {
        yres = xres;
      }

      /* make best-effort guess at what parameters will look like once
         scanning starts.  */
      if (xres > 0 && yres > 0 && width > 0 && length > 0)
      {
        DBG (11, "sane_get_parameters: width='%d', xres='%d', mud='%d'\n",
             width, xres, s->hw->info.mud);
        s->params.pixels_per_line = width * xres / s->hw->info.mud;
        DBG (11, "sane_get_parameters: length='%d', yres='%d', mud='%d'\n",
             length, yres, s->hw->info.mud);
        s->params.lines = length * yres / s->hw->info.mud;
        DBG (11, "sane_get_parameters: pixels_per_line='%d', lines='%d'\n",
             s->params.pixels_per_line, s->params.lines);
      }

      mode = s->val[OPT_MODE].s;
      if (strcmp (mode, "Lineart") == 0 || strcmp (mode, "Halftone") == 0)
      {
        s->params.format = SANE_FRAME_GRAY;
        s->params.bytes_per_line = s->params.pixels_per_line / 8;
        /* workaround rounding problems */
        s->params.pixels_per_line = s->params.bytes_per_line * 8;
        s->params.depth = 1;
      }
      else if (strcmp (mode, "Gray") == 0)
      {
        s->params.format = SANE_FRAME_GRAY;
        s->params.bytes_per_line = s->params.pixels_per_line;
        s->params.depth = 8;
      }
      else if (strcmp (mode, "Color") == 0
             || strcmp (mode, "Fine color") == 0)
      {
        s->params.format = SANE_FRAME_RGB;
        s->params.bytes_per_line = 3 * s->params.pixels_per_line;
        s->params.depth = 8;
      }
      else
      {
        s->params.format = SANE_FRAME_RGB;
        s->params.bytes_per_line = 6 * s->params.pixels_per_line;
        s->params.depth = 16;
      }
      s->params.last_frame = SANE_TRUE;
    }

  DBG (11,
       "sane_get_parameters: xres='%d', yres='%d', pixels_per_line='%d', bytes_per_line='%d', lines='%d'\n",
       s->xres, s->yres, s->params.pixels_per_line, s->params.bytes_per_line,
       s->params.lines);

  if (params)
    *params = s->params;

  DBG (1, "<< sane_get_parameters\n");
  return (SANE_STATUS_GOOD);
}

/**************************************************************************/

SANE_Status
sane_start (SANE_Handle handle)
{
  int mode;
  char *mode_str;
  CANON_Scanner *s = handle;
  SANE_Status status;
  u_char wbuf[72], dbuf[28], ebuf[72];
  u_char cbuf[2];       /* modification for FB620S */
  size_t buf_size, i;

  char tmpfilename[] = "/tmp/canon.XXXXXX"; /* for FB1200S */
  char *thistmpfile; /* for FB1200S */

  DBG (1, ">> sane_start\n");

  s->tmpfile = -1; /* for FB1200S */

/******* making a tempfile for 1200 dpi scanning of FB1200S ******/
  if (s->hw->info.model == FB1200)
   {
     thistmpfile = strdup(tmpfilename);

    if (thistmpfile != NULL)
     {
     if (mktemp(thistmpfile) == 0)
      {
       DBG(1, "mktemp(thistmpfile) is failed\n");
       return (SANE_STATUS_INVAL);
      }
     }
    else
     {
       DBG(1, "strdup(thistmpfile) is failed\n");
       return (SANE_STATUS_INVAL);
     }

    s->tmpfile = open(thistmpfile, O_RDWR | O_CREAT | O_EXCL, 0600);

     if (s->tmpfile == -1)
      {
       DBG(1, "error opening temp file %s\n", thistmpfile);
       DBG(1, "errno: %i; %s\n", errno, strerror(errno));
       errno = 0;
       return (SANE_STATUS_INVAL);
      }
      DBG(1, " ****** tmpfile is opened ****** \n");

    unlink(thistmpfile);
    free (thistmpfile);
    DBG(1, "free thistmpfile\n");
   }
/******************************************************************/

  s->scanning = SANE_FALSE;

  if ((s->hw->adf.Status == SANE_TRUE)
      && (s->val[OPT_FLATBED_ONLY].w != SANE_TRUE)
      && (s->hw->adf.Problem != 0))
    {
      DBG (3, "SCANNER ADF HAS A PROBLEM\n");
      if (s->hw->adf.Problem & 0x08)
      {
        status = SANE_STATUS_COVER_OPEN;
        DBG (3, "ADF Cover Open\n");
      }
      else if (s->hw->adf.Problem & 0x04)
      {
        status = SANE_STATUS_JAMMED;
        DBG (3, "ADF Paper Jam\n");
      }
      else              /* adf.Problem = 0x02 */
      {
        status = SANE_STATUS_NO_DOCS;
        DBG (3, "ADF No More Documents\n");
      }
      return status;
    }
  else if ((s->hw->adf.Status == SANE_TRUE)
         && (s->val[OPT_FLATBED_ONLY].w == SANE_TRUE))
    {
      set_adf_mode (s->fd, s->hw->adf.Priority);
      /* 2.23 define ADF Mode */
    }

  /* First make sure we have a current parameter set.  Some of the
     parameters will be overwritten below, but that's OK.  */
  status = sane_get_parameters (s, 0);
  if (status != SANE_STATUS_GOOD)
    return status;

  status = sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, s->hw);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "open of %s failed: %s\n",
         s->hw->sane.name, sane_strstatus (status));
      return (status);
    }

  /* Do focus, but not for the preview */
  if (SANE_OPTION_IS_ACTIVE(s->opt[OPT_FOCUS_GROUP].cap)
    && (s->val[OPT_PREVIEW].w == SANE_FALSE) && (s->AF_NOW == SANE_TRUE))
    {
      if ((status = do_focus (s)) != SANE_STATUS_GOOD) return (status);
      if (s->val[OPT_AF_ONCE].w == SANE_TRUE)
      {
        s->AF_NOW = SANE_FALSE;
      }
    }

  if (s->val[OPT_CUSTOM_GAMMA].w == 1)
    {
      if ((status = do_gamma (s)) != SANE_STATUS_GOOD) return (status);
    }

#if 1
  DBG (3, "attach: sending GET SCAN MODE for scan control conditions\n");
  memset (ebuf, 0, sizeof (ebuf));
  buf_size = 20;
  status = get_scan_mode (s->fd, (u_char) SCAN_CONTROL_CONDITIONS,
    ebuf, &buf_size);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "attach: GET SCAN MODE for scan control conditions failed\n");
      sanei_scsi_close (s->fd);
      return (SANE_STATUS_INVAL);
    }
  for (i = 0; i < buf_size; i++)
    {
      DBG (3, "scan mode control byte[%lu] = %d\n", (u_long) i, ebuf[i]);
    }

  if (s->hw->adf.Status != ADF_STAT_NONE)
    {
      DBG (3, "attach: sending GET SCAN MODE for transparency unit\n");
      memset (ebuf, 0, sizeof (ebuf));
      buf_size = 12;
      status = get_scan_mode (s->fd, (u_char) TRANSPARENCY_UNIT,
                        ebuf, &buf_size);
      if (status != SANE_STATUS_GOOD)
      {
        DBG (1, "attach: GET SCAN MODE for transparency unit failed\n");
        sanei_scsi_close (s->fd);
        return (SANE_STATUS_INVAL);
      }
      for (i = 0; i < buf_size; i++)
      {
        DBG (3, "scan mode control byte[%lu] = %d\n", (u_long) i, ebuf[i]);
      }
    }
#endif


  mode_str = s->val[OPT_MODE].s;
  s->xres = s->val[OPT_X_RESOLUTION].w;
  s->yres = s->val[OPT_Y_RESOLUTION].w;

  if ((s->val[OPT_RESOLUTION_BIND].w == SANE_TRUE)
      || (s->val[OPT_PREVIEW].w == SANE_TRUE))
    {
      s->yres = s->xres;
    }

  s->ulx = SANE_UNFIX (s->val[OPT_TL_X].w) * s->hw->info.mud / MM_PER_INCH;
  s->uly = SANE_UNFIX (s->val[OPT_TL_Y].w) * s->hw->info.mud / MM_PER_INCH;

  s->width = SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w)
    * s->hw->info.mud / MM_PER_INCH;
  s->length = SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w)
    * s->hw->info.mud / MM_PER_INCH;

  DBG (11, "s->width='%d', s->length='%d'\n", s->width, s->length);

  if (s->hw->info.model != CS2700 && s->hw->info.model != FS2710)
    {
      if ((strcmp (mode_str, "Lineart") == 0) ||
        (strcmp (mode_str, "Halftone") == 0))
      {
        s->RIF = s->val[OPT_HNEGATIVE].w;
      }
      else
      {
        s->RIF = !s->val[OPT_HNEGATIVE].w;
      }
    }

  s->brightness = s->val[OPT_BRIGHTNESS].w;
  s->contrast = s->val[OPT_CONTRAST].w;
  s->threshold = s->val[OPT_THRESHOLD].w;
  s->bpp = s->params.depth;


  s->GRC = s->val[OPT_CUSTOM_GAMMA].w;
  s->Mirror = s->val[OPT_MIRROR].w;
  s->AE = s->val[OPT_AE].w;


  s->HiliteG = s->val[OPT_HILITE_G].w;
  s->ShadowG = s->val[OPT_SHADOW_G].w;
  if (s->val[OPT_BIND_HILO].w == SANE_TRUE)
    {
      s->HiliteR = s->val[OPT_HILITE_G].w;
      s->ShadowR = s->val[OPT_SHADOW_G].w;
      s->HiliteB = s->val[OPT_HILITE_G].w;
      s->ShadowB = s->val[OPT_SHADOW_G].w;
    }
  else
    {
      s->HiliteR = s->val[OPT_HILITE_R].w;
      s->ShadowR = s->val[OPT_SHADOW_R].w;
      s->HiliteB = s->val[OPT_HILITE_B].w;
      s->ShadowB = s->val[OPT_SHADOW_B].w;
    }

  if (strcmp (mode_str, "Lineart") == 0)
    {
      mode = 4;
      s->image_composition = 0;
    }
  else if (strcmp (mode_str, "Halftone") == 0)
    {
      mode = 4;
      s->image_composition = 1;
    }
  else if (strcmp (mode_str, "Gray") == 0)
    {
      mode = 5;
      s->image_composition = 2;
    }
  else if (strcmp (mode_str, "Color") == 0 ||
         strcmp (mode_str, "Fine color") == 0)
    {
      mode = 6;
      s->image_composition = 5;
    }
  else if (strcmp (mode_str, "Raw") == 0)
    {
      mode = 6;
      s->image_composition = 5;
    }
  else
    {
      mode = 6;
      s->image_composition = 5;
    }

  memset (wbuf, 0, sizeof (wbuf));
  wbuf[7] = 64;
  wbuf[10] = s->xres >> 8;
  wbuf[11] = s->xres;
  wbuf[12] = s->yres >> 8;
  wbuf[13] = s->yres;
  wbuf[14] = s->ulx >> 24;
  wbuf[15] = s->ulx >> 16;
  wbuf[16] = s->ulx >> 8;
  wbuf[17] = s->ulx;
  wbuf[18] = s->uly >> 24;
  wbuf[19] = s->uly >> 16;
  wbuf[20] = s->uly >> 8;
  wbuf[21] = s->uly;
  wbuf[22] = s->width >> 24;
  wbuf[23] = s->width >> 16;
  wbuf[24] = s->width >> 8;
  wbuf[25] = s->width;
  wbuf[26] = s->length >> 24;
  wbuf[27] = s->length >> 16;
  wbuf[28] = s->length >> 8;
  wbuf[29] = s->length;
  wbuf[30] = s->brightness;
  wbuf[31] = s->threshold;
  wbuf[32] = s->contrast;
  wbuf[33] = s->image_composition;
  wbuf[34] = (s->hw->info.model == FS2710) ? 12 : s->bpp;
  wbuf[36] = 1;
  wbuf[37] = (1 << 7) + 0x3;
  wbuf[50] = (s->GRC << 3) | (s->Mirror << 2);
  /* For preview, don't set AE, so that scanning speed is normal */
  if (s->val[OPT_PREVIEW].w == SANE_FALSE)
    {
      wbuf[50] |= s->AE;
    }
  wbuf[54] = 2;
  wbuf[57] = 1;
  wbuf[58] = 1;
  wbuf[59] = s->HiliteR;
  wbuf[60] = s->ShadowR;
  wbuf[62] = s->HiliteG;
  wbuf[64] = s->ShadowG;
  wbuf[70] = s->HiliteB;
  wbuf[71] = s->ShadowB;

  DBG (7, "RIF=%d, GRC=%d, Mirror=%d, AE=%d\n",
       s->RIF, s->GRC, s->Mirror, s->AE);
  DBG (7, "HR=%d, SR=%d, HG=%d, SG=%d, HB=%d, SB=%d\n",
       s->HiliteR, s->ShadowR,
       s->HiliteG, s->ShadowG, s->HiliteB, s->ShadowB);

  if (s->hw->info.model == FB620)   /* modification for FB620S */
    {
      wbuf[36] = 0;
      wbuf[37] = (s->RIF << 7) + 0x3;
      wbuf[50] = s->GRC << 3;
      wbuf[54] = 0;
      wbuf[57] = 0;
      wbuf[58] = 0;
    }
  else if (s->hw->info.model == FB1200)   /* modification for FB1200S */
    {
/*    wbuf[34] = (((600 < s->val[OPT_X_RESOLUTION].w) || (600 < s->val[OPT_Y_RESOLUTION].w)) && (strcmp (s->val[OPT_MODE].s, "Lineart") != 0)) ? 12 : s->bpp; */
      wbuf[36] = 0;
      wbuf[37] = (s->RIF << 7) + 0x3;
      wbuf[50] = (1 << 4) | (s->GRC << 3);
      wbuf[57] = 1;
      wbuf[58] = 1;
    }

  buf_size = sizeof (wbuf);
  status = set_window (s->fd, wbuf);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "SET WINDOW failed: %s\n", sane_strstatus (status));
      return (status);
    }
  if (s->hw->info.model == FS2710)
    status = set_parameters_fs2710 (s);
  buf_size = sizeof (wbuf);
  memset (wbuf, 0, buf_size);
  status = get_window (s->fd, wbuf, &buf_size);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "GET WINDOW failed: %s\n", sane_strstatus (status));
      return (status);
    }
  DBG (5, "xres=%d\n", (wbuf[10] << 8) + wbuf[11]);
  DBG (5, "yres=%d\n", (wbuf[12] << 8) + wbuf[13]);
  DBG (5, "ulx=%d\n", (wbuf[14] << 24) + (wbuf[15] << 16) + (wbuf[16] << 8)
    + wbuf[17]);
  DBG (5, "uly=%d\n", (wbuf[18] << 24) + (wbuf[19] << 16) + (wbuf[20] << 8)
    + wbuf[21]);
  DBG (5, "width=%d\n", (wbuf[22] << 24) + (wbuf[23] << 16) + (wbuf[24] << 8)
    + wbuf[25]);
  DBG (5, "length=%d\n", (wbuf[26] << 24) + (wbuf[27] << 16) + (wbuf[28] << 8)
    + wbuf[29]);
  DBG (5, "Highlight Red=%d\n", wbuf[59]);
  DBG (5, "Shadow Red=%d\n", wbuf[60]);
  DBG (5, "Highlight (Green)=%d\n", wbuf[62]);
  DBG (5, "Shadow (Green)=%d\n", wbuf[64]);
  DBG (5, "Highlight Blue=%d\n", wbuf[70]);
  DBG (5, "Shadow Blue=%d\n", wbuf[71]);

  if (s->hw->tpu.Status == TPU_STAT_ACTIVE)
    {
      DBG (3,
         "sane_start: sending DEFINE SCAN MODE for transparency unit, \
NP=%d, Negative film type=%d\n", !s->RIF, s->negative_filmtype);
      memset (wbuf, 0, sizeof (wbuf));
      wbuf[0] = 0x02;
      wbuf[1] = 6;
      wbuf[2] = 0x80;
      wbuf[3] = 0x05;
      wbuf[4] = 39;
      wbuf[5] = 16;
      wbuf[6] = !s->RIF;
      wbuf[7] = s->negative_filmtype;
      status = define_scan_mode (s->fd, TRANSPARENCY_UNIT, wbuf);
      /* note: If we implement a TPU for the FB1200S, we need
         TRANSPARENCY_UNIT_FB1200 here. */
      if (status != SANE_STATUS_GOOD)
      {
        DBG (1, "define scan mode failed: %s\n", sane_strstatus (status));
        return (status);
      }
    }

#if 1
  DBG (3,
       "sane_start: sending DEFINE SCAN MODE for scan control conditions\n");
  memset (wbuf, 0, sizeof (wbuf));
  if (s->hw->info.model == FB1200)
    {
      wbuf[0] = 0x20;
      wbuf[1] = 17;
      wbuf[16] = 3;
      wbuf[17] = 8;
      wbuf[18] = (1 << 7) | (1 << 3);

      DBG (3,
       "sane_start: sending DEFINE SCAN MODE for scan control conditions of FB1200\n");
      status = define_scan_mode (s->fd, SCAN_CONTROL_CON_FB1200, wbuf);
      if (status != SANE_STATUS_GOOD)
        {
          DBG (1, "define scan mode failed: %s\n", sane_strstatus (status));
          return (status);
        }
    }
  else
    {
      wbuf[0] = 0x20;
      wbuf[1] = 14;
      wbuf[15] = (s->hw->info.model == FB620 && strcmp (mode_str, "Fine color")
      == 0 && s->val[OPT_PREVIEW].w == SANE_FALSE) ? 1 << 3 : 0;

      /* For preview use always normal speed: */
      if (s->val[OPT_PREVIEW].w == SANE_FALSE)
        wbuf[11] = s->scanning_speed;
      status = define_scan_mode (s->fd, SCAN_CONTROL_CONDITIONS, wbuf);
      if (status != SANE_STATUS_GOOD)
        {
          DBG (1, "define scan mode failed: %s\n", sane_strstatus (status));
          return (status);
        }
    }

  DBG (3, "sane_start: sending GET SCAN MODE for scan control conditions\n");
  memset (ebuf, 0, sizeof (ebuf));
  buf_size = sizeof (ebuf);
  status = get_scan_mode (s->fd, SCAN_CONTROL_CONDITIONS, ebuf, &buf_size);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1,
         "sane_start: GET SCAN MODE for scan control conditions failed\n");
      sanei_scsi_close (s->fd);
      return (SANE_STATUS_INVAL);
    }
  for (i = 0; i < buf_size; i++)
    {
      DBG (3, "scan mode byte[%lu] = %d\n", (u_long) i, ebuf[i]);
    }
#endif

/* ============= modification for FB620S ============= */

  DBG (3, "TEST_UNIT_READY\n");
  status = test_unit_ready (s->fd);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "test unit ready failed (%s)\n", sane_strstatus (status));
      sanei_scsi_close (s->fd);
      s->fd = -1;
      return (status);
    }

  if (s->hw->info.can_calibrate)
    {
      DBG (3, "sane_start: sending GET_CALIBRATION_STATUS\n");
      buf_size = sizeof (cbuf);
      memset (cbuf, 0, buf_size);
      status = get_calibration_status (s->fd, cbuf, &buf_size);
      if (status != SANE_STATUS_GOOD)
      {
        DBG (1, "sane_start: GET_CALIBRATION_STATUS failed: %s\n",
             sane_strstatus (status));
        sanei_scsi_close (s->fd);
        s->fd = -1;
        return (status);
      }

      DBG (1, "cbuf[0] = %d\n", cbuf[0]);
      DBG (1, "cbuf[1] = %d\n", cbuf[1]);

      cbuf[0] &= 3;
      if (cbuf[0] == 1 || cbuf[0] == 2 || cbuf[0] == 3)
      {
        status = execute_calibration (s->fd);
        DBG (3, "sane_start: EXECUTE_CALIBRATION\n");
        if (status != SANE_STATUS_GOOD)
          {
            DBG (1, "sane_start: EXECUTE_CALIBRATION failed\n");
            sanei_scsi_close (s->fd);
            s->fd = -1;
            return (status);
          }

        DBG (3, "after calibration: GET_CALIBRATION_STATUS\n");
        buf_size = sizeof (cbuf);
        memset (cbuf, 0, buf_size);
        status = get_calibration_status (s->fd, cbuf, &buf_size);
        if (status != SANE_STATUS_GOOD)
          {
            DBG (1,
               "after calibration: GET_CALIBRATION_STATUS failed: %s\n",
               sane_strstatus (status));
            sanei_scsi_close (s->fd);
            s->fd = -1;
            return (status);
          }
        DBG (1, "cbuf[0] = %d\n", cbuf[0]);
        DBG (1, "cbuf[1] = %d\n", cbuf[1]);
      }
    }

  status = scan (s->fd);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "start of scan failed: %s\n", sane_strstatus (status));
      return (status);
    }

  buf_size = sizeof (dbuf);
  memset (dbuf, 0, buf_size);
  status = get_data_status (s->fd, dbuf, &buf_size);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "GET DATA STATUS failed: %s\n", sane_strstatus (status));
      return (status);
    }
  DBG (5, ">> GET DATA STATUS\n");
  DBG (5, "Scan Data Available=%d\n", (dbuf[9] << 16) + (dbuf[10] << 8)
       + dbuf[11]);
  DBG (5, "Magnified Width=%d\n", (dbuf[12] <<24) + (dbuf[13] << 16)
       + (dbuf[14] << 8) + dbuf[15]);
  DBG (5, "Magnified Length=%d\n", (dbuf[16] << 24) + (dbuf[17] << 16)
       + (dbuf[18] << 8) + dbuf[19]);
  DBG (5, "Rest Data=%d bytes\n", (dbuf[20] << 24) + (dbuf[21] << 16)
       + (dbuf[22] << 8) + dbuf[23]);
  DBG (5, "Filled Data Buffer=%d\n", (dbuf[24] << 24) + (dbuf[25] << 16)
       + (dbuf[26] << 8) + dbuf[27]);
  DBG (5, "<< GET DATA STATUS\n");

  s->bytes_to_read = s->params.bytes_per_line * s->params.lines;

  if (s->hw->info.model == FB1200)
    {
      if (s->bytes_to_read != (((size_t)dbuf[9] << 16) + ((size_t)dbuf[10] << 8)
      + (size_t)dbuf[11]))
      {
        s->params.bytes_per_line = (((size_t) dbuf[12] << 24)
        + ((size_t) dbuf[13] << 16) + ((size_t) dbuf[14] << 8)
        + (size_t)dbuf[15]);
        s->params.lines = (((size_t) dbuf[16] << 24)
        + ((size_t) dbuf[17] << 16) + ((size_t) dbuf[18] << 8)
        + (size_t) dbuf[19]);
        s->bytes_to_read = s->params.bytes_per_line * s->params.lines;

        mode_str = s->val[OPT_MODE].s;
        if (strcmp (mode_str, "Lineart") == 0)
          {
            if (((600 < s->val[OPT_X_RESOLUTION].w)
            || (600 < s->val[OPT_Y_RESOLUTION].w)))
            {
              s->params.bytes_per_line *= 2;
              s->params.lines /= 2;
            }
            s->params.pixels_per_line = s->params.bytes_per_line * 8;
          }
        else if (strcmp (mode_str, "Gray") == 0)
            s->params.pixels_per_line = s->params.bytes_per_line;
        else if (strcmp (mode_str, "Color") == 0
        || strcmp (mode_str, "Fine color") == 0)
            s->params.pixels_per_line = s->params.bytes_per_line / 3;
        else
            s->params.pixels_per_line = s->params.bytes_per_line / 6;
      }
    }

  DBG (1, "%d pixels per line, %d bytes, %d lines high, total %lu bytes, "
       "dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line,
       s->params.lines, (u_long) s->bytes_to_read,
       s->val[OPT_X_RESOLUTION].w);

/**************************************************/
/* modification for FB620S and FB1200S */
  s->buf_used = 0;
  s->buf_pos = 0;
/**************************************************/

  s->scanning = SANE_TRUE;

  DBG (1, "<< sane_start\n");
  return (SANE_STATUS_GOOD);
}

/**************************************************************************/

static SANE_Status
sane_read_direct (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
              SANE_Int * len)
{
  CANON_Scanner *s = handle;
  SANE_Status status;
  size_t nread;

  DBG (21, ">> sane_read\n");

  *len = 0;
  nread = max_len;

  DBG (21, "   sane_read: nread=%lu, bytes_to_read=%lu\n", (u_long) nread,
       (u_long) s->bytes_to_read);
  if (s->bytes_to_read == 0)
    {
      do_cancel (s);
      return (SANE_STATUS_EOF);
    }

  if (!s->scanning)
    return (do_cancel (s));

  if (nread > s->bytes_to_read)
    nread = s->bytes_to_read;
  status = read_data (s->fd, buf, &nread);
  if (status != SANE_STATUS_GOOD)
    {
      do_cancel (s);
      return (SANE_STATUS_IO_ERROR);
    }
  *len = nread;
  s->bytes_to_read -= nread;

  DBG (21, "   sane_read: nread=%lu, bytes_to_read=%lu\n", (u_long) nread,
       (u_long) s->bytes_to_read);
  DBG (21, "<< sane_read\n");
  return (SANE_STATUS_GOOD);
}

/**************************************************************************/

static SANE_Status
read_fs2710 (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
           SANE_Int * len)
{
  CANON_Scanner *s = handle;
  SANE_Status status;
  int c;
  size_t i, nread, nread2;
  u_char *p, b;

  DBG (21, ">> sane_read\n");

  *len = 0;
  nread = max_len;

  DBG (21, "   sane_read: nread=%lu, bytes_to_read=%lu\n", (u_long) nread,
       (u_long) s->bytes_to_read);

  if (nread > s->bytes_to_read)
    nread = s->bytes_to_read;
  if (s->bytes_to_read == 0)
    {
      do_cancel (s);
      return (SANE_STATUS_EOF);
    }

  if (!s->scanning)
    return (do_cancel (s));

  /* We must receive 2 bytes per pixel and colour. In raw mode we
     must swap the bytes (for compatibility with xsane) and pass
     them both. Otherwise the other subroutines expect only 1 byte,
     so we must set up an intermediate buffer which is twice as large
     as buf, and then map this buffer to buf. */

  if (strcmp (s->val[OPT_MODE].s, "Color") == 0)
    {
      if (max_len > s->auxbuf_len)
      {                 /* extend buffer? */
        if (s->auxbuf_len > 0)
          free (s->auxbuf);
        s->auxbuf_len = max_len;
        if ((s->auxbuf = (u_char *) malloc (2 * max_len)) == NULL)
          {
            DBG (1, "sane_read buffer size insufficient\n");
            do_cancel (s);
            return SANE_STATUS_NO_MEM;
            /*exit(1); */
          }
      }

      nread2 = 2 * nread;
      if ((status =
         read_data (s->fd, s->auxbuf, &nread2)) != SANE_STATUS_GOOD)
      {
        do_cancel (s);
        return (SANE_STATUS_IO_ERROR);
      }
      nread = nread2 / 2;
      for (i = 0, p = s->auxbuf; i < nread; i++)
      {
        c = *p++ >> 4;
        c |= *p++ << 4;
        *buf++ = s->gamma_map[s->colour++][c];
        if (s->colour > 3)
          s->colour = 1;      /* cycle through RGB */
      }
    }
  else
    {
      if ((status = read_data (s->fd, buf, &nread)) != SANE_STATUS_GOOD)
      {
        do_cancel (s);
        return (SANE_STATUS_IO_ERROR);
      }
      for (p = buf; p < buf + nread; p++)
      {
        b = *p;
        *p++ = *(p + 1);
        *p = b;
      }
    }
  *len = nread;
  s->bytes_to_read -= nread;

  DBG (21, "   sane_read: nread=%lu, bytes_to_read=%lu\n", (u_long) nread,
       (u_long) s->bytes_to_read);
  DBG (21, "<< sane_read\n");
  return (SANE_STATUS_GOOD);
}

/**************************************************************************/
/* modification for FB620S */

static SANE_Status
read_fb620 (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
          SANE_Int * len)
{
  CANON_Scanner *s = handle;
  SANE_Status status;
  SANE_Byte *out, *red, *green, *blue;
  SANE_Int ncopy;
  size_t nread = 0, i, pixel_per_line;

  DBG (21, ">> read_fb620\n");

  *len = 0;

  DBG (21, "   read_fb620: nread=%lu, bytes_to_read=%lu\n", (u_long) nread,
       (u_long) s->bytes_to_read);

  if (s->bytes_to_read == 0 && s->buf_pos == s->buf_used)
    {
      s->reset_flag = 0;      /* no reset */

      do_cancel (s);
      DBG (21, "do_cancel(EOF)\n");
      DBG (21, "reset_flag = %d\n", s->reset_flag);
      return (SANE_STATUS_EOF);
    }
  else
    {
      s->reset_flag = 1;      /* do reset */
      DBG (21, "reset_flag = %d\n", s->reset_flag);
    }
  DBG (21, "   read_fb620: buf_pos=%d, buf_used=%d\n", s->buf_pos,
       s->buf_used);

  if (!s->scanning)
    return (do_cancel (s));

  if (s->buf_pos < s->buf_used)
    {
      ncopy = s->buf_used - s->buf_pos;
      if (ncopy > max_len)
      ncopy = max_len;
      memcpy (buf, &(s->outbuffer[s->buf_pos]), ncopy);

      max_len -= ncopy;
      *len += ncopy;
      buf = &(buf[ncopy]);
      s->buf_pos += ncopy;
    }

  if (s->buf_pos >= s->buf_used && s->bytes_to_read)
    {
      /* buffer is empty: read in scan line and sort color data as shown
         above */

      nread = s->params.bytes_per_line;

      if (nread > s->bytes_to_read)
      nread = s->bytes_to_read;

      status = read_data (s->fd, s->inbuffer, &nread);

      if (status != SANE_STATUS_GOOD)
      {
        do_cancel (s);
        return (SANE_STATUS_IO_ERROR);
      }

      s->buf_used = s->params.bytes_per_line;

      out = s->outbuffer;
      pixel_per_line = s->params.pixels_per_line;

      red = s->inbuffer;
      green = &(s->inbuffer[pixel_per_line]);
      blue = &(s->inbuffer[2 * pixel_per_line]);

      for (i = 0; i < pixel_per_line; i++)
      {
        *out++ = *red++;
        *out++ = *green++;
        *out++ = *blue++;
      }

      s->buf_pos = 0;

      s->bytes_to_read -= s->buf_used;

    }

  if (max_len && s->buf_pos < s->buf_used)
    {
      ncopy = s->buf_used - s->buf_pos;
      if (ncopy > max_len)
      ncopy = max_len;
      memcpy (buf, &(s->outbuffer[s->buf_pos]), ncopy);
      *len += ncopy;
      s->buf_pos += ncopy;
    }

  DBG (21, "<< read_fb620\n");
  return (SANE_STATUS_GOOD);
}

/**************************************************************************/
/* modification for FB1200S */

static SANE_Status
read_fb1200 (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
SANE_Int * len)
{
  CANON_Scanner *s = handle;
  SANE_Status status;
  SANE_Byte *firstimage, *secondimage/*, inmask, outmask, outbyte, primaryHigh[256], primaryLow[256], secondaryHigh[256], secondaryLow[256] */;
  SANE_Int ncopy;
  
  u_char dbuf[28];
  size_t buf_size, nread, remain, nwritten, nremain, pos, pix, pixel_per_line,
       byte, byte_per_line/*, bit*/;
  ssize_t wres, readres;
  int maxpix;

  DBG (21, ">> read_fb1200\n");

  buf_size = sizeof (dbuf);
  memset (dbuf, 0, buf_size);
  status = get_data_status (s->fd, dbuf, &buf_size);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "GET DATA STATUS failed: %s\n", sane_strstatus (status));
      return (status);
    }
  DBG (5, ">> GET DATA STATUS\n");
  DBG (5, "Scan Data Available=%d\n", (dbuf[9] << 16) + (dbuf[10] << 8)
    + dbuf[11]);
  DBG (5, "Rest Data=%d bytes\n", (dbuf[20] << 24) + (dbuf[21] << 16)
    + (dbuf[22] << 8) + dbuf[23]);
  DBG (5, "Filled Data Buffer=%d\n", (dbuf[24] << 24) + (dbuf[25] << 16)
    + (dbuf[26] << 8) + dbuf[27]);
  DBG (5, "temp file position:%lu\n", (u_long) lseek(s->tmpfile, 0, SEEK_CUR));
  DBG (5, "<< GET DATA STATUS\n");

  *len = 0;

  DBG (21, "   read_fb1200: nread=%lu, bytes_to_read=%lu\n", (u_long) nread,
       (u_long) s->bytes_to_read);

  if (s->bytes_to_read == 0 && s->buf_pos == s->buf_used)
    {
      do_cancel (s);
      DBG (21, "do_cancel(EOF)\n");
      return (SANE_STATUS_EOF);
    }

  DBG (21, "   read_fb1200: buf_pos=%d, buf_used=%d\n", s->buf_pos,
       s->buf_used);

  if (!s->scanning)
    return (do_cancel (s));

  if (s->buf_pos >= s->buf_used && s->bytes_to_read)
    {
      nread = s->params.bytes_per_line / 2;

      if (nread > s->bytes_to_read)
      nread = s->bytes_to_read;

      status = read_data (s->fd, s->inbuffer, &nread);

      if (status != SANE_STATUS_GOOD)
      {
        do_cancel (s);
        return (SANE_STATUS_IO_ERROR);
      }

/**** save the primary scan data to tmpfile ****/

     if ((SANE_Int) s->bytes_to_read > s->params.bytes_per_line
       * s->params.lines / 2)
       {
         remain = nread;
         nwritten = 0;
         while (remain)
          {
           errno = 0;
           wres = write (s->tmpfile, &s->inbuffer[nwritten], remain);
           if (wres == -1)
            {
             DBG(1, "error write tmp file: %i, %s\n", errno, strerror(errno));
             do_cancel(s);
             return (SANE_STATUS_NO_MEM);
            }
           remain -= wres;
           nwritten += wres;
          }

        s->bytes_to_read -= nread;

        if ((SANE_Int) s->bytes_to_read <= s->params.bytes_per_line
        * s->params.lines / 2)
          {
            if ((SANE_Int) s->bytes_to_read < s->params.bytes_per_line
            * s->params.lines / 2)
              {
                DBG(1, "warning: read more data for the primary scan than expected\n");
              }

           lseek (s->tmpfile, 0L, SEEK_SET);
           *len = 0;
           *buf = 0;
           return (SANE_STATUS_GOOD);
         }

        DBG(1, "writing: the primary data to tmp file\n");
        *len = 0;
        *buf = 0;
        return (SANE_STATUS_GOOD);
      }
/** the primary scan data from tmpfile and the secondary scan data are mreged **/

      s->buf_used = s->params.bytes_per_line;
      byte_per_line = s->params.bytes_per_line;
      pixel_per_line = s->params.pixels_per_line;


/** read an entire scan line from the primary scan **/

      remain = nread;
      pos = 0;
      firstimage = &(s->inbuffer[byte_per_line/2]);

      while (remain > 0)
       {
        nremain = (remain < SSIZE_MAX)? remain: SSIZE_MAX;
        errno = 0;
        readres = read (s->tmpfile, &(firstimage[pos]), nremain);
        if (readres == -1)
         {
          DBG(1, "error reading tmp file: %i %s\n", errno, strerror(errno));
          do_cancel(s);
          return (SANE_STATUS_IO_ERROR);
         }
        if (readres == 0)
         {
          DBG(1, "0 byte read from temp file. premature EOF?\n");
          return (SANE_STATUS_INVAL);
         /* perhaps an error return? */
         }
         DBG(1, "reading: the primary data from tmp file\n");
         remain -= readres;
         pos += readres;
       }

      secondimage = s->inbuffer;

      if (strcmp (s->val[OPT_MODE].s, "Color") == 0)
       {
        maxpix = pixel_per_line / 2;
        for (pix = 0; (int) pix < maxpix; pix++)
         {
           s->outbuffer[6 * pix] = secondimage[3 * pix];
           s->outbuffer[6 * pix + 1] = secondimage[3 * pix + 1];
           s->outbuffer[6 * pix + 2] = secondimage[3 * pix + 2];
           s->outbuffer[6 * pix + 3] = firstimage[3 * pix];
           s->outbuffer[6 * pix + 4] = firstimage[3 * pix + 1];
           s->outbuffer[6 * pix + 5] = firstimage[3 * pix + 2];
       }
       }
      else if (strcmp (s->val[OPT_MODE].s, "Gray") == 0)
       {
        for (pix = 0; pix < pixel_per_line / 2; pix++)
         {
           s->outbuffer[2 * pix] = secondimage[pix];
           s->outbuffer[2 * pix + 1] = firstimage[pix];
       }
       }
      else /* for lineart mode */
       {
        maxpix = byte_per_line / 2;
        for (byte = 0; (int) byte < maxpix; byte++)
         {
        s->outbuffer[2 * byte] = primaryHigh[firstimage[byte]]
          | secondaryHigh[secondimage[byte]];
        s->outbuffer[2 * byte + 1] = primaryLow[firstimage[byte]]
          | secondaryLow[secondimage[byte]];
/*
          inmask = 128;
          outmask = 128;
          outbyte = 0;
          for (bit = 0; bit < 4; bit++)
           {
            if (inmask == (secondimage[byte] & inmask))
              outbyte = outbyte | outmask;
            outmask = outmask >> 1;
            if (inmask == (firstimage[byte] & inmask))
              outbyte = outbyte | outmask;
            outmask = outmask >> 1;

            inmask = inmask >> 1;
           }
          s->outbuffer[2 * byte] = outbyte;

          outmask = 128;
          outbyte = 0;
          for (bit = 0; bit < 4; bit++)
           {
            if (inmask == (secondimage[byte] & inmask))
              outbyte = outbyte | outmask;
            outmask = outmask >> 1;
            if (inmask == (firstimage[byte] & inmask))
              outbyte = outbyte | outmask;
            outmask = outmask >> 1;

            inmask = inmask >> 1;
           }
          s->outbuffer[2 * byte + 1] = outbyte;
*/
         }
       }

      s->buf_pos = 0;
      s->bytes_to_read -= nread;
    }

  if (max_len && s->buf_pos < s->buf_used)
    {
      ncopy = s->buf_used - s->buf_pos;
      if (ncopy > max_len)
      ncopy = max_len;
      memcpy (buf, &(s->outbuffer[s->buf_pos]), ncopy * 2);
      *len += ncopy;
      s->buf_pos += ncopy;
    }

  DBG (21, "<< read_fb1200\n");
  return (SANE_STATUS_GOOD);
}

/**************************************************************************/
SANE_Status
sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
         SANE_Int * len)
{
  CANON_Scanner *s = handle;
  SANE_Status status;
  if (s->hw->info.model == FB620 && s->params.format == SANE_FRAME_RGB)
    status = read_fb620 (handle, buf, max_len, len);
  else if (s->hw->info.model == FS2710)
    status = read_fs2710 (handle, buf, max_len, len);
  else if (s->hw->info.model == FB1200 && ((600 < s->val[OPT_X_RESOLUTION].w)
  || (600 < s->val[OPT_Y_RESOLUTION].w)))
    status = read_fb1200 (handle, buf, max_len, len);
  else
    status = sane_read_direct (handle, buf, max_len, len);
  if (s->time0 == -1)
    s->time0 = 0;
  else
    time (&(s->time0));

  DBG (11, "sane_read: time0 = %ld\n", (u_long) s->time0);
  s->switch_preview = s->val[OPT_PREVIEW].w;
  return (status);
}

/**************************************************************************/

void
sane_cancel (SANE_Handle handle)
{
  CANON_Scanner *s = handle;
  DBG (1, ">> sane_cancel\n");

/******** for FB1200S ************/
  if(s->hw->info.model == FB1200)
   {
    if (s->tmpfile != -1)
     {
      close (s->tmpfile);
      DBG(1, " ****** tmpfile is closed ****** \n");
     }
    else
     {
      DBG(1, "tmpfile is failed\n");
/*    return (SANE_STATUS_INVAL);*/
     }
   }
/*********************************/

  s->scanning = SANE_FALSE;
  DBG (1, "<< sane_cancel\n");
}

/**************************************************************************/

SANE_Status
sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
{
  DBG (1, ">> sane_set_io_mode\n");
  DBG (1, "<< sane_set_io_mode\n");
  return SANE_STATUS_UNSUPPORTED;
}

/**************************************************************************/

SANE_Status
sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
{
  DBG (1, ">> sane_get_select_fd\n");
  DBG (1, "<< sane_get_select_fd\n");

  return SANE_STATUS_UNSUPPORTED;
}

/**************************************************************************/

Generated by  Doxygen 1.6.0   Back to index