/* sane - Scanner Access Now Easy.

   Copyright (C) 2006 -2008 Gerard Klaver  <gerard at gkall dot hobby dot nl>
   For the usb commands, add_text (xawtv (webcam) and parts of the stv680 
   sane backend are used.
   
   This file is part of the SANE package.
   
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.
   
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
   MA 02111-1307, USA.
   
   */

/*  $Id: sq930x.c,v 1.5 2008/05/02 15:09:43 gerard Exp $

   sq930x vidcam  driver Gerard Klaver
*/

/*SANE FLOW DIAGRAM

   - sane_init() : initialize backend, attach vidcams
   . - sane_get_devices() : query list of vidcam devices
   . - sane_open() : open a particular vidcam device
   . . - sane_set_io_mode : set blocking mode
   . . - sane_get_select_fd : get vidcam fd
   . . - sane_get_option_descriptor() : get option information
   . . - sane_control_option() : change option values
   . .
   . . - sane_start() : start image acquisition
   . .   - sane_get_parameters() : returns actual scan parameters
   . .   - sane_read() : read image data (from pipe)
   . .     (sane_read called multiple times; 
   . .      after sane_read returns EOF)
   . .     go back to sane_start() if more frames desired
   . . - sane_cancel() : cancel operation
   . - sane_close() : close opened vidcam device
   - sane_exit() : terminate use of backend
*/
/*--------------------------------------------------------------------------*/

#define BUILD 5			/* 2006/04/14  update 02-05-2008 */
#define BACKEND_NAME sq930x
#define SQ930X_CONFIG_FILE "sq930x.conf"

/* --------------------- SANE INTERNATIONALISATION ------------------------ */

/* must be first include */
#include "../include/sane/config.h"

#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "../include/sane/sane.h"
#include "../include/sane/sanei.h"
#include "../include/sane/saneopts.h"
#include "../include/sane/sanei_usb.h"
#include "../include/sane/sanei_debug.h"
#include "../include/sane/sanei_backend.h"
#include "../include/sane/sanei_config.h"
#include "../include/sane/sanei_jpeg.h"
#include "../include/lassert.h"

/* for add-text routine  */
#include <time.h>
#include "../include/font_6x11.h"
/*-----------------------*/

#include "sq930x.h"

#define TIMEOUT 1000

/*--------------------------------------------------------------------------*/
/* Lists of possible scan modes. */
static SANE_String_Const scan_mode_list[] = {
  COLOR_RGB_STR,
  SANE_VALUE_SCAN_MODE_COLOR,
  COLOR_RAW_STR,

  NULL
};

/*-----------------------------------------minium, maximum, quantization----*/
static const SANE_Range brightness_range = { -128, 128, 1 };

static const SANE_Range red_level_range = { -32, 32, 1 };

static const SANE_Range green_level_range = { -32, 32, 1 };

static const SANE_Range blue_level_range = { -32, 32, 1 };

/* List of text options. */
static SANE_String_Const text_list[] = {
  "No text",
  "Text",
  NULL
};

static const int text_val[] = {
  0x00,
  0x01
};

/* List of decomp options. */
static SANE_String_Const decomp_list[] = {
  "RGB24",
  "I420",
  NULL
};

static const int decomp_val[] = {
  0x00,
  0x01
};

/* List of read_format options. */
static SANE_String_Const read_format_list[] = {
  ".BMP",
  ".JPG",
  NULL
};

static const int read_format_val[] = {
  0x00,
  0x01
};

/*--------------------------------------------------------------------------*/

/* Used for jpeg decompression */
/*static struct jpeg_decompress_struct cinfo;
static djpeg_dest_ptr dest_mgr = NULL;
*/

/* Cameras with CCD sensors only appear to support three resolutions.
 * On top of that, we only have the init sequence for the 640x480 setting
 * Others are for the future */

static const struct dpi_color_adjust sq930x_ccd_dpi_color_adjust[] = {

  /*dpi, y, x, color sequence R G or B */
  {640, 480, 0, 1, 2},		/* VGA             */
  {320, 240, 0, 1, 2},		/* QVGA (SIF)      */
  {160, 120, 0, 1, 2},		/* QSIF            */
  /* must be the last entry */
  {0, 0, 0, 0, 0}
};

static const struct dpi_color_adjust sq930x_cmos_dpi_color_adjust[] = {

  /*dpi, y, x, color sequence R G or B */
  {640, 480, 0, 1, 2},		/* VGA             */
  {352, 288, 0, 1, 2},		/* CIF             */
  {320, 240, 0, 1, 2},		/* QVGA (SIF)      */
  {176, 144, 0, 1, 2},		/* QCIF            */
  {160, 120, 0, 1, 2},		/* QSIF            */
  /* must be the last entry */
  {0, 0, 0, 0, 0}
};

static const struct dpi_color_adjust sq930x_cmos_mi360_dpi_color_adjust[] = {

  /*dpi, y, x, color sequence R G or B */
  {640, 480, 2, 1, 0},		/* VGA             */
  {352, 288, 2, 1, 0},		/* CIF             */
  {320, 240, 2, 1, 0},		/* QVGA (SIF)      */
  {176, 144, 2, 1, 0},		/* QCIF            */
  {160, 120, 2, 1, 0},		/* QSIF            */
  /* must be the last entry */
  {0, 0, 0, 0, 0}
};

static const struct vidcam_hardware vidcams[] = {

  {0x041e, 0x403c, USB_CLASS_VENDOR_SPEC, Sq930x_creative_ultra_notebook,
   "Creative", "Live! Ultra",
   sq930x_ccd_dpi_color_adjust},

  {0x041e, 0x403d, USB_CLASS_VENDOR_SPEC, Sq930x_creative_ultra_notebook,
   "Creative", "Live! Ultra for Notebooks",
   sq930x_ccd_dpi_color_adjust},

  {0x041e, 0x4041, USB_CLASS_VENDOR_SPEC, Sq930x_creative_live_motion,
   "Creative", "Live! Motion",
   sq930x_ccd_dpi_color_adjust},

  {0x041e, 0x4038, USB_CLASS_VENDOR_SPEC, Sq930x_MI360,
   "Creative/Joy-IT", "Live! Pro\?\?318S",
   sq930x_cmos_dpi_color_adjust},

  {0x2770, 0x930b, USB_CLASS_VENDOR_SPEC, Sq930x_sweex_motion_tracking,
   "Sweex/Typhoon", "Motion Tracking/MotionCam",
   sq930x_cmos_dpi_color_adjust},

  {0x2770, 0x930c, USB_CLASS_VENDOR_SPEC, Sq930x_trust_3500t,	/* test modelTrust WB-3500T */
   "Trust/TECOM/NSG", "WB-3500T/318S-H (NHJ)/Robbie 2.0",
   sq930x_cmos_mi360_dpi_color_adjust}
};

/* List of vidcams attached. */
static Sq930x_Vidcam *first_dev = NULL;
static int num_devices = 0;
/* used by sane_get_devices */
static const SANE_Device **devlist = NULL;

/*static uint8_t rgb[640*480*3]; */

/*----------------------------------------------------------- */

/* Local functions. */

/* Display a buffer in the log. Display by lines of 16 bytes. */
static void
hexdump (int level, const char *comment, unsigned char *buf, const int length)
{
  int i;
  char line[128];
  char *ptr;
  char asc_buf[17];
  char *asc_ptr;

  DBG (level, "  %s\n", comment);

  i = 0;
  goto start;

  do
    {
      if (i < length)
	{
	  ptr += sprintf (ptr, " %2.2x", *buf);

	  if (*buf >= 32 && *buf <= 127)
	    {
	      asc_ptr += sprintf (asc_ptr, "%c", *buf);
	    }
	  else
	    {
	      asc_ptr += sprintf (asc_ptr, ".");
	    }
	}
      else
	{
	  /* After the length; do nothing. */
	  ptr += sprintf (ptr, "   ");
	}

      i++;
      buf++;

      if ((i % 16) == 0)
	{
	  /* It's a new line */
	  DBG (level, "  %s    %s\n", line, asc_buf);

	start:
	  ptr = line;
	  *ptr = '\0';
	  asc_ptr = asc_buf;
	  *asc_ptr = '\0';

	  ptr += sprintf (ptr, "  %3.3d:", i);
	}
    }
  while (i < ((length + 15) & ~15));
}

/* Returns the length of the longest string, including the terminating
 * character. */
static size_t
max_string_size (SANE_String_Const strings[])
{
  size_t size, max_size = 0;
  int i;

  for (i = 0; strings[i]; ++i)
    {
      size = strlen (strings[i]) + 1;
      if (size > max_size)
	{
	  max_size = size;
	}
    }
  return max_size;
}

/* Lookup a string list from one array and return its index. */
static int
get_string_list_index (SANE_String_Const list[], SANE_String_Const name)
{
  int index;

  index = 0;
  while (list[index] != NULL)
    {
      if (strcmp (list[index], name) == 0)
	{
	  return (index);
	}
      index++;
    }

  DBG (DBG_error, "name %s not found in list\n", name);

  assert (0 == 1);		/* bug in backend, core dump */

  return (-1);
}

/* Initialize a vidcam entry. Return an allocated vidcam with some
 *  */
static Sq930x_Vidcam *
sq930x_init (void)
{
  Sq930x_Vidcam *dev;

  DBG (DBG_proc, "sq930x_init: enter\n");

  /* Allocate a new vidcam entry. */
  dev = malloc (sizeof (Sq930x_Vidcam));
  if (dev == NULL)
    {
      return NULL;
    }
  memset (dev, 0, sizeof (Sq930x_Vidcam));

/* Allocate the windoww buffer*/
  dev->windoww_size = 0x20;
  dev->windoww = malloc (dev->windoww_size);
  if (dev->windoww == NULL)
    {
      free (dev);
      return NULL;
    }

/* Allocate the windowr buffer*/
  dev->windowr_size = 0x20;
  dev->windowr = malloc (dev->windowr_size);
  if (dev->windowr == NULL)
    {
      free (dev);
      free (dev->windoww);
      return NULL;
    }

  dev->fd = -1;

  DBG (DBG_proc, "sq930x_init: exit\n");

  return (dev);
}

static SANE_Status
sq930x_init_2 (Sq930x_Vidcam * dev)
{
  SANE_Status status;

  DBG (DBG_proc, "sq930x_init_2: enter\n");

  /* Allocate the buffer used to transfer the USB data */
  /* Check for max. format image size so buffer size can
   * be adjusted, format from camera is BA81 */
  /* dev->buffer_size = (640 * 480 * dev->bytes_pixel) + 0x8; */
  dev->buffer_size = 659 * 494;	/* changed due some different sensor sizes */
  DBG (DBG_proc, "sq930x_init_2: dev->bufffer = 0x%lx\n",
       (unsigned long) (size_t) dev->buffer_size);

  dev->buffer = malloc (dev->buffer_size);

  if (dev->buffer == NULL)
    {
      free (dev);
      free (dev->windowr);
      free (dev->windoww);
      return SANE_STATUS_NO_MEM;
    }

  /* Allocate the output buffer used for bayer conversion */
  dev->output_size = dev->buffer_size * 3;

  dev->output = malloc (dev->output_size);
  if (dev->output == NULL)
    {
      free (dev);
      free (dev->windowr);
      free (dev->windoww);
      free (dev->buffer);

      return SANE_STATUS_NO_MEM;
    }
  dev->image_size = dev->buffer_size * 3;

  dev->image = malloc (dev->image_size);
  if (dev->image == NULL)
    {
      free (dev);
      free (dev->windowr);
      free (dev->windoww);
      free (dev->buffer);
      free (dev->output);

      return SANE_STATUS_NO_MEM;
    }

  DBG (DBG_proc, "sq930x_init_2: exit\n");
  status = SANE_STATUS_GOOD;
  return status;
}

/* Closes an open vidcams. */
static void
sq930x_close (Sq930x_Vidcam * dev)
{
  DBG (DBG_proc, "sq930x_close: enter \n");

  if (dev->fd != -1)
    {

      DBG (DBG_proc, "sq930x_close: fd !=-1 \n");
      sanei_usb_close (dev->fd);
      dev->fd = -1;
    }

  DBG (DBG_proc, "sq930x_close: exit\n");
}

/* Frees the memory used by a vidcam. */
static void
sq930x_free (Sq930x_Vidcam * dev)
{
  int i;

  DBG (DBG_proc, "sq930x_free: enter\n");

  if (dev == NULL)
    return;

  sq930x_close (dev);
  if (dev->devicename)
    {
      free (dev->devicename);
    }
  if (dev->buffer)
    {
      free (dev->buffer);
    }
  if (dev->output)
    {
      free (dev->output);
    }
  if (dev->image)
    {
      free (dev->image);
    }
  if (dev->windoww)
    {
      free (dev->windoww);
    }
  if (dev->windowr)
    {
      free (dev->windowr);
    }
  for (i = 1; i < OPT_NUM_OPTIONS; i++)
    {
      if (dev->opt[i].type == SANE_TYPE_STRING && dev->val[i].s)
	{
	  free (dev->val[i].s);
	}
    }
  if (dev->resolutions_list)
    free (dev->resolutions_list);

  free (dev);

  DBG (DBG_proc, "sq930x_free: exit\n");
}

/* Reset vidcam */
static SANE_Status
sq930x_reset_vidcam (Sq930x_Vidcam * dev)
{
  SANE_Status status;
  size_t sizew;			/* significant size of window */
  size_t sizer;

  DBG (DBG_proc, "sq930x_reset_vidcam: enter\n");

  sizew = dev->windoww_size;
  sizer = dev->windowr_size;

  memset (dev->windoww, 0, sizew);
  memset (dev->windowr, 0, sizer);

  status = SANE_STATUS_GOOD;
  DBG (DBG_proc, "sq930x_reset_vidcam: exit\n");

  return status;
}

/* Inquiry a device and returns TRUE if is supported. */
static int
sq930x_identify_vidcam (Sq930x_Vidcam * dev)
{
  SANE_Status status;
  SANE_Word vendor;
  SANE_Word product;
  int i;
  size_t sizer;
  size_t sizew;
  int reg1_mask;
  int read_count, count;

  DBG (DBG_info, "sq930x_identify_vidcam: open\n");

  sizew = dev->windoww_size;
  sizer = dev->windowr_size;

  memset (dev->windoww, 0, sizew);
  memset (dev->windowr, 0, sizer);

  usleep (2000);

  status = sanei_usb_get_vendor_product (dev->fd, &vendor, &product);

  /* Loop through our list to make sure this scanner is supported. */
  for (i = 0; i < NELEMS (vidcams); i++)
    {
      if (vidcams[i].vendor == vendor && vidcams[i].product == product)
	{

	  DBG (DBG_info, "sq930x_identify_vidcam: vidcam %x:%x is in list\n",
	       vendor, product);

	  dev->hw = &(vidcams[i]);

	  sizer = dev->windowr_size;
	  memset (dev->windowr, 0, sizer);

/* urb 4  read data 
   * [1040 ms/  >>>  URB 4 going down  >>> 
   * 03 00 12 93 0b f6 c9 00   snif from live! ultra
   * 03 00 07 93 0b f6 ca 00   result from live! ultra for notebook
   * 02 00 07 93 0b f6 ca 00   result from live! ultra for notebook
   * 03 00 12 93 0b fe c8 00   result from Trust WB-3500T, chip text 930c
   * 02 00 12 93 0b fe c8 00   result from Trust WB-3500T, chip text 930c
   * 02 00 06 93 0b fe c8 00   result from Joy-IT 318S, chip text 930c
   * 02 00 12 93 0b fe cf 00   result from ProQ Motion Webcam
   * * byte
   * 1. 02 usb 1.0 (12Mbit), 03 usb2.0 (480Mbit)
   * 2. 00
   * 3. 06 07 12 -- mode webcam? firmware??
   * 4. 93	chip? 930b (930b or 930c)
   * 5. 0b
   * 6. f6 ???? fe ???? ccd/cmos???
   * 7. c8, c9, ca cf -- mode webcam?, sensor? webcam?
   * 8. 00
   *  	      
*/
	  usleep (2000);
	  switch (dev->hw->sq930_sensor_ref)
	    {
	    case Sq930x_trust_3500t:
	    case Sq930x_MI360:
	    case Sq930x_sweex_motion_tracking:
	      sizew = 0x08;	/* check size data for write */
	      status =
		sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x001e, 0x0000,
				       sizew, dev->windoww);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb4 error\n");
		  return status;
		}
	      DBG (DBG_proc, "sq930x_identify_vidcam: urb4 end\n");

	      sizer = 0x08;
	      status =
		sanei_usb_control_msg (dev->fd, 0xc0, 0x0c, 0x001f, 0x0000,
				       sizer, dev->windowr);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb5 error\n");
		  return status;
		}
	      hexdump (DBG_info2,
		       "urb5: output example\n 03 00 12 93 0b f6 c9 00,\n if your result is different,\n check with urb 5 table in source code,\n for new values, please let me know,\n (with camera info)\n urb5: output\n",
		       dev->windowr, sizer);

	      DBG (DBG_info,
		   "sq930x_identify_vidcam: exit vidcam supported\n");
	      status = SANE_TRUE;

	      break;

	    case Sq930x_creative_ultra_notebook:
	    case Sq930x_creative_live_motion:
	      sizer = 0x08;
	      status =
		sanei_usb_control_msg (dev->fd, 0xc0, 0x0c, 0x001f, 0x0000,
				       sizer, dev->windowr);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb4 error\n");
		  return status;
		}
	      hexdump (DBG_info2,
		       "urb4:  03 00 12 93 0b f6 c9 00, if your result is different,\n check with urb 4 table in source code,\n for new values, please let me know (with camera info)",
		       dev->windowr, sizer);
	      usleep (2000);
	      sizew = 0x00;
	      status =
		sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x3101, 0x00f0,
				       sizew, dev->windoww);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb5 error\n");
		  return status;
		}
	      DBG (DBG_proc, "sq930x_identify_vidcam: urb5 end\n");

	      usleep (2000);

	      sizew = 0x00;
	      status =
		sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0305, 0xfd00,
				       sizew, dev->windoww);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb6 error\n");
		  return status;
		}
	      DBG (DBG_proc, "sq930x_identify_vidcam: urb6 end\n");

	      usleep (2000);
	      /*
	         [1052 ms]  >>>  URB 7 going down  >>> 
	         [1052 ms]  <<<  URB 7 coming back  <<< 
	         SetupPacket          =
	         00000000: 40 0c 05 01 00 bf 00 00
	       */
	      if (dev->hw->sq930_sensor_ref == Sq930x_creative_live_motion)
		reg1_mask = 0xfc;
	      else
		reg1_mask = 0xb8;
	      sizew = 0x00;
	      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, (reg1_mask | 7) << 8,	/* was 0xbf00, */
					      sizew, dev->windoww);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb7 error\n");
		  return status;
		}
	      DBG (DBG_proc, "sq930x_identify_vidcam: urb7 end\n");
	      usleep (2000);
	      /*
	         [1102 ms]  >>>  URB 8 going down same as urb129?  >>> 
	         TransferBufferLength = 00000015
	         00000000: fa 03 00 00 f8 02 01 f8 be 02 f8 c6 04 f8 00 08
	         00000010: f8 00 09 f8 06
	         TransferBufferLength = 00000015
	         SetupPacket          =
	         00000000: 40 0c 01 54 03 00 15 00
	       */
	      usleep (2000);
	      sizew = sizeof (urb_init_8);
	      memcpy (dev->windoww, urb_init_8, sizew);
	      status =
		sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x5401, 0x0003,
				       sizew, dev->windoww);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb8 error\n");
		  return status;
		}
	      DBG (DBG_proc, "sq930x_identify_vidcam: urb8 end\n");
	      usleep (2000);
/*
[1105 ms]  >>>  URB 9 going down  >>> 
  SetupPacket          =
    00000000: 40 0c 05 01 00 bf 00 00
*/
	      sizew = 0x00;
	      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, (reg1_mask | 7) << 8,	/* was 0xbf00, */
					      sizew, dev->windoww);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb9 error\n");
		  return status;
		}
	      DBG (DBG_proc, "sq930x_identify_vidcam: urb9 end\n");
	      usleep (2000);
	      /*
	         [1107 ms]  <<<  URB 10 coming back  <<< 
	         SetupPacket          =
	         00000000: 40 0c 05 01 00 bc 00 00
	       */
	      sizew = 0x00;
	      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, (reg1_mask | 4) << 8,	/* was 0xbc00, */
					      sizew, dev->windoww);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb10 error\n");
		  return status;
		}
	      DBG (DBG_proc, "sq930x_identify_vidcam: urb10 end\n");

	      usleep (2000);

	      /*
	         [1113 ms]  >>>  URB 11 going down  >>> 
	         00000000: 40 0c 05 01 00 be 00 00
	       */

	      sizew = 0x00;
	      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, (reg1_mask | 6) << 8,	/* was 0xbe00, */
					      sizew, dev->windoww);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb11\n");
		  return status;
		}
	      DBG (DBG_proc, "sq930x_identify_vidcam: urb11 end\n");
	      usleep (2000);

	      /*
	         [1119 ms]  <<<  URB 12 coming back  <<< 
	         SetupPacket          =
	         00000000: 40 0c 05 01 00 bf 00 00
	       */

	      sizew = 0x00;
	      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, (reg1_mask | 7) << 8,	/* was 0xbf00, */
					      sizew, dev->windoww);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb12\n");
		  return status;
		}
	      DBG (DBG_proc, "sq930x_identify_vidcam: urb12 end\n");
	      usleep (2000);
	      /*
	         [1124 ms]  >>>  URB 13 going down  >>> 
	         SetupPacket          =
	         00000000: 40 0c 05 01 00 bb 00 00
	       */

	      sizew = 0x00;
	      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, (reg1_mask | 3) << 8,	/* was 0xbb00, */
					      sizew, dev->windoww);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb13\n");
		  return status;
		}
	      DBG (DBG_proc, "sq930x_identify_vidcam: urb13 end\n");
	      /*  
	         [1226 ms] UsbSnoop - DispatchAny(eb780610) : IRP_MJ_PNP (IRP_MN_QUERY_INTERFACE)
	       */
	      /*
	         [5609 ms]  >>>  URB 14 going down  >>> 
	         00000000: 03 00 12 93 0b f6 c9 00
	         SetupPacket          =
	         00000000: c0 0c 1f 00 00 00 08 00
	         check status string ??
	         * urb 14... urb120 reason ??
	         [43835 ms]  >>>  URB 120 going down  read >>> 
	       */
	      usleep (2000);
	      sizew = 0x00;
	      status =
		sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x3101, 0x00f0,
				       sizew, dev->windoww);
	      if (status != SANE_STATUS_GOOD)
		{
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb14\n");
		  return status;
		}
	      DBG (DBG_proc, "sq930x_identify_vidcam: urb14 end\n");
/*
usleep (460000);
count=0;
read_count= 0x5;
	      
for (count = 0; count < read_count; count++)
	{
sizer=0x08;
  status =
    sanei_usb_control_msg (dev->fd, 0xc0, 0x0c, 0x001f, 0x0000, sizer,
			   dev->windowr);
  if (status != SANE_STATUS_GOOD)
    {
	    DBG (DBG_proc, "sq930x_vidcam_init: urb14-120 error\n");
      return status;
    }
  DBG (DBG_proc, "sq930x_identify_vidcam: urb14-120 end, read_count=%d\n", count);
sizer = 0x08;
hexdump (DBG_info2, "urb14-120 03 00 12 93 0b f6 c9 00", dev->windowr, sizer);

usleep (50000);
	} 
*/
	      if (dev->hw->sq930_sensor_ref == Sq930x_creative_live_motion)
		{
		  sizew = 0x00;
		  status =
		    sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x3101,
					   0x00ff, sizew, dev->windoww);
		  if (status != SANE_STATUS_GOOD)
		    {
		      DBG (DBG_proc, "sq930x_identify_vidcam: urb14\n");
		      return status;
		    }
		  DBG (DBG_proc, "sq930x_identify_vidcam: urb14 end\n");
		}
	      DBG (DBG_info,
		   "sq930x_identify_vidcam: exit vidcam supported\n");
	      return SANE_TRUE;
	      status = SANE_TRUE;
	      break;
	    }
	  return status;
	}
    }
  DBG (DBG_error, "sq930x_identify_vidcam: exit this is not a SQ930X exit\n");
  return SANE_FALSE;
}

static SANE_Status
sq930x_vidcam_init (Sq930x_Vidcam * dev)
{
  SANE_Status status;
  SANE_Byte i = 0;
  SANE_Byte val = 0;
  size_t sizer;
  size_t sizew;
  int reg1_mask;

  DBG (DBG_proc, "sq930x_vidcam_init: open\n");

  sizew = dev->windoww_size;
  sizer = dev->windowr_size;

  memset (dev->windoww, 0, sizew);
  memset (dev->windowr, 0, sizer);

  switch (dev->hw->sq930_sensor_ref)
    {
    case Sq930x_trust_3500t:
    case Sq930x_MI360:
    case Sq930x_sweex_motion_tracking:
      usleep (1000);
/* [44071 ms]  >>>  URB 16  >>> */
      sizew = 0x00;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0305, 0xfd00, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb16\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb16 end\n");
/* [44071 ms]  >>>  URB 17  >>> */
      sizew = 0x00;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, 0x7b00, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb17\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb17 end\n");
/* [44071 ms]  >>>  URB 18  >>> */
      sizew = 0x00;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, 0x7c00, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb18\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb18 end\n");
/* [44071 ms]  >>>  URB 19  >>> */
      sizew = 0x00;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, 0x7e00, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb19\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb19 end\n");
/* [44071 ms]  >>>  URB 20  >>> */
      sizew = 0x00;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, 0x7f00, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb20\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb20 end\n");
/* [44071 ms]  >>>  URB 21  >>> */
      sizew = 0x00;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, 0x7f00, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb21\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb21 end\n");
      usleep (2000);
/* [44083 ms]  >>>  URB 22  >>> */
      sizew = sizeof (urb_init_22);
      memcpy (dev->windoww, urb_init_22, sizew);

      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x5401, 0x0003, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb22\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb22 end\n");
/* [44083 ms]  >>>  URB 23  >>> */
      sizew = sizeof (urb_init_23);
      memcpy (dev->windoww, urb_init_23, sizew);

      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x5d02, 0x0030, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb23\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb23 end\n");
/* [44083 ms]  >>>  URB 24  >>> */
      sizew = sizeof (urb_init_24);
      memcpy (dev->windoww, urb_init_24, sizew);

      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x5d02, 0x0103, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb24\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb24 end\n");
/* [44083 ms]  >>>  URB 25  >>> */
      sizew = sizeof (urb_init_25);
      memcpy (dev->windoww, urb_init_25, sizew);

      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x355d, 0x1200, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb25\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb25 end\n");
/* [44083 ms]  >>>  URB 26  >>> */
      sizew = sizeof (urb_init_142a);
      memcpy (dev->windoww, urb_init_142a, sizew);

      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0xf001, 0x11f5, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb26\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb26 end\n");
/* [44083 ms]  >>>  URB 27  >>> */
      sizew = sizeof (urb_init_142a);
      memcpy (dev->windoww, urb_init_142a, sizew);

      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0xf001, 0x51f5, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb27\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb27 end\n");
/* [44083 ms]  >>>  URB 28  >>> */
      sizew = sizeof (urb_init_144);
      memcpy (dev->windoww, urb_init_144, sizew);

      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0xfa01, 0x00f5, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb28\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb28 end\n");
      usleep (2000);
/* [ ms]  >>>  URB 29 going down  >>> */
      sizew = 0x02;
      dev->windoww[0] = 0x80;
      dev->windoww[1] = 0x1d;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x5d02, 0x0462, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb29\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb29 end\n");
      usleep (2000);
      /* [ ms]  >>>  URB 30 going down  >>> */
      sizew = 0x02;
      dev->windoww[0] = 0x80;
      dev->windoww[1] = 0x7d;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x5d02, 0x0005, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb30\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb30 end\n");
      usleep (2000);
/* urb 31 data copy from urb 34 */
      sizew = sizeof (urb_init_34);
      memcpy (dev->windoww, urb_init_34, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x1a10, 0x0502, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb31\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb31 end\n");
      usleep (2000);
      /* urb 32 */
      sizer = 0x00;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0011, 0x0000, sizer,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb32\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb32 end\n");

      usleep (2000);

      /* [ 45295ms]  >>>  URB 33 going down  >>> */
      sizew = 0x02;
      dev->windoww[0] = 0x80;
      dev->windoww[1] = 0xf5;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x055d, 0x0203, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb33\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb33 end\n");

      usleep (2000);

      /* [45303ms] urb 34 */
      sizew = sizeof (urb_init_34);
      memcpy (dev->windoww, urb_init_34, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x1a10, 0x0502, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb34 wrong\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb34 end\n");
      usleep (2000);
      break;

    case Sq930x_creative_ultra_notebook:
    case Sq930x_creative_live_motion:
      usleep (2000);
/*
    [44019 ms]  >>>  URB 122  urb 15 lun going down  >>> 
  SetupPacket          =
    00000000: 40 0c 05 03 00 fd 00 00
    */
      sizew = 0x00;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0305, 0xfd00, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb122 15\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb122 15 end\n");
      usleep (2000);

      if (dev->hw->sq930_sensor_ref == Sq930x_creative_live_motion)
	reg1_mask = 0xfc;
      else
	reg1_mask = 0xb8;
      /*
         [44019 ms]  >>>  URB 123  urb16 lun going down  >>> 
         SetupPacket          =
         00000000: 40 0c 05 01 00 bf 00 00
       */
      sizew = 0x00;
      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, (reg1_mask | 7) << 8,	/* was 0xbf00, */
				      sizew, dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb123\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb123 16 end\n");
      usleep (2000);
      /*  
         [44069 ms]  >>>  URB 124 urb 17 lun going down  >>> 
         [44070 ms]  <<<  URB 124 coming back  <<< 
         SetupPacket          =
         00000000: 40 0c 05 01 00 bf 00 00
       */
      sizew = 0x00;
      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, (reg1_mask | 7) << 8,	/*was 0xbf00, */
				      sizew, dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb124\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb124 end 17\n");
      usleep (2000);
/*
    [44071 ms]  >>>  URB 125 urb 18 lun going down  >>> 
[44072 ms]  <<<  URB 125 coming back  <<< 
  SetupPacket          =
    00000000: 40 0c 05 01 00 bc 00 00
*/
      sizew = 0x00;
      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, (reg1_mask | 4) << 8,	/* was 0xbc00, */
				      sizew, dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb125\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb125 18end\n");
      usleep (2000);
      /*
         [44077 ms]  >>>  URB 126 urb 19 lun going down  >>> 
         SetupPacket          =
         00000000: 40 0c 05 01 00 be 00 00
       */
      sizew = 0x00;
      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, (reg1_mask | 6) << 8,	/* was 0xbe00, */
				      sizew, dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb126\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb126 19 end\n");
      usleep (2000);
/*
    [44083 ms]  >>>  URB 127 urb 20 lun going down  >>> 
  SetupPacket          =
    00000000: 40 0c 05 01 00 bf 00 00
*/
      sizew = 0x00;
      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, (reg1_mask | 7) << 8,	/* was 0xbf00, */
				      sizew, dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb127\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb127 20 end\n");
      usleep (2000);
/*
[44089 ms]  >>>  URB 128 urb 21 lun going down  >>> 
  SetupPacket          =
    00000000: 40 0c 05 01 00 bb 00 00
*/
      sizew = 0x00;
      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0105, (reg1_mask | 3) << 8,	/*was 0xbb00, */
				      sizew, dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb128\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb128 21 end\n");

      usleep (2000);
/*
    [44190 ms]  >>>  URB 129 urb 22 lun going down  >>> 
    00000000: fa 03 00 00 f8 02 01 f8 be 02 f8 c6 04 f8 00 08
    00000010: f8 00 09 f8 06
[44191 ms]  <<<  URB 129 coming back  <<< 
  SetupPacket          =
    00000000: 40 0c 01 54 03 00 15 00
*/
      sizew = sizeof (urb_init_129);
      memcpy (dev->windoww, urb_init_129, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x5401, 0x0003, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb129\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb129 22 end\n");
      usleep (2000);
      /*
         [44192 ms]  >>>  URB 130 urb 23 lun going down  >>> 
         00000000: 0b f8 fe 07 f8 84 0c f8 02 0d f8 f7 0e f8 03 0f
         00000010: f8 0b 1c f8 00
         [44193 ms]  <<<  URB 130 coming back  <<< 
         SetupPacket          =
         00000000: 40 0c 01 0a f8 01 15 00
       */
      sizew = sizeof (urb_init_130);
      memcpy (dev->windoww, urb_init_130, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0a01, 0x01f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb130\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb130 23 end\n");
      usleep (2000);
      /*
         [44195 ms]  >>>  URB 131 urb 24 lun going down  >>> 
         00000000: 1e f8 03 1f f8 0b 3a f8 00 3b f8 01 3c f8 00 3d
         00000010: f8 6b 10 f8 03
         [44196 ms]  <<<  URB 131 coming back  <<< 
         SetupPacket          =
         00000000: 40 0c 01 1d f8 49 15 00
       */
      sizew = sizeof (urb_init_131);
      memcpy (dev->windoww, urb_init_131, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x1d01, 0x49f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb131\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb131 24 end\n");
      usleep (2000);
/*
    [44197 ms]  >>>  URB 132 urb 25 lun going down  >>> 
    00000000: 12 f8 02 13 f8 6f 03 f8 00 14 f8 00 15 f8 44 16
    00000010: f8 00 17 f8 48
[44198 ms]  <<<  URB 132 coming back  <<< 
  SetupPacket          =
    00000000: 40 0c 01 11 f8 10 15 00
    */
      sizew = sizeof (urb_init_132);
      memcpy (dev->windoww, urb_init_132, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x1101, 0x10f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb132\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb132 25 end\n");
      usleep (2000);
      /*
         [44200 ms]  >>>  URB 133 urb 26 lun going down  >>> 
         00000000: 19 f8 25 1a f8 00 1b f8 3c 2f f8 03 20 f8 ff 21
         00000010: f8 0d 22 f8 ff
         [44201 ms]  <<<  URB 133 coming back  <<< 
         SetupPacket          =
         00000000: 40 0c 01 18 f8 00 15 00
       */
      sizew = sizeof (urb_init_133);
      memcpy (dev->windoww, urb_init_133, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x1801, 0x00f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb133\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb133 26 end\n");
      usleep (2000);
/*
    [44202 ms]  >>>  URB 134 urb 27 lun going down  >>> 
    00000000: 24 f8 fd 25 f8 07 26 f8 f0 27 f8 0c 28 f8 ff 29
    00000010: f8 03 2a f8 ff
[44203 ms]  <<<  URB 134 coming back  <<< 
  SetupPacket          =
    00000000: 40 0c 01 23 f8 07 15 00
  */
      sizew = sizeof (urb_init_134);
      memcpy (dev->windoww, urb_init_134, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x2301, 0x07f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb134\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb134 27 end\n");
      usleep (2000);
      /*
         [44205 ms]  >>>  URB 135 urb 28 lun going down  >>> 
         00000000: 2c f8 fc 2d f8 01 2e f8 00 30 f8 00 31 f8 47 32
         00000010: f8 00 33 f8 00
         [44206 ms]  <<<  URB 135 coming back  <<< 
         SetupPacket          =
         00000000: 40 0c 01 2b f8 0c 15 00
       */
      sizew = sizeof (urb_init_135);
      memcpy (dev->windoww, urb_init_135, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x2b01, 0x0cf8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb135\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb135 28 end\n");
/*
    [44207 ms]  >>>  URB 136 urb 29 lun going down  >>> 
    00000000: 51 f8 00 52 f8 00 53 f8 24 54 f8 00 55 f8 0c 56
    00000010: f8 00 57 f8 30
[44208 ms]  <<<  URB 136 coming back  <<< 
  SetupPacket          =
    00000000: 40 0c 01 50 f8 00 15 00
  */
      sizew = sizeof (urb_init_136);
      memcpy (dev->windoww, urb_init_136, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x5001, 0x00f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb136\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb136 29 end\n");
      usleep (2000);
      /* 
         [44210 ms]  >>>  URB 137 urb30 lun going down  >>> 
         00000000: 59 f8 18 5a f8 00 5b f8 3c 5c f8 00 5d f8 18 5e
         00000010: f8 00 5f f8 3c
         [44211 ms]  <<<  URB 137 coming back  <<< 
         SetupPacket          =
         00000000: 40 0c 01 58 f8 00 15 00
       */
      sizew = sizeof (urb_init_137);
      memcpy (dev->windoww, urb_init_137, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x5801, 0x00f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb137\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb137 30 end\n");
      /*  
         [44212 ms]  >>>  URB 138 urb 31 lun going down  >>> 
         00000000: 61 f8 37 62 f8 ff 63 f8 1d 64 f8 ff 65 f8 98 66
         00000010: f8 ff 67 f8 c0
         [44213 ms]  <<<  URB 138 coming back  <<< 
         SetupPacket          =
         00000000: 40 0c 01 60 f8 ff 15 00
       */
      sizew = sizeof (urb_init_138);
      memcpy (dev->windoww, urb_init_138, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x6001, 0xfff8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb138\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb138 31 end\n");
      /*
         [44215 ms]  >>>  URB 139 urb 32 lun going down  >>> 
         00000000: 69 f8 37 6c f8 02 6d f8 1d 6a f8 00 6b f8 37 6e
         00000010: f8 02 6f f8 1d
         [44216 ms]  <<<  URB 139 coming back  <<< 
         SetupPacket          =
         00000000: 40 0c 01 68 f8 00 15 00
       */
      sizew = sizeof (urb_init_139);
      memcpy (dev->windoww, urb_init_139, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x6801, 0x00f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb139\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb139 32 end\n");
      /* 
         [44218 ms]  >>>  URB 140 urb 33 lun going down  >>> 
         00000000: 71 f8 c6 72 f8 02 73 f8 04 74 f8 01 75 f8 c6 76
         00000010: f8 02 77 f8 04
         [44219 ms]  <<<  URB 140 coming back  <<< 
         SetupPacket          =
         00000000: 40 0c 01 70 f8 01 15 00
       */
      sizew = sizeof (urb_init_140);
      memcpy (dev->windoww, urb_init_140, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x7001, 0x01f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb140\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb140 33 end\n");
      /*
         [44221 ms]  >>>  URB 141 urb 34 lun going down  >>> 
         00000000: 79 f8 0f 7a f8 ff 7b f8 ff 00 f8 03
         [44222 ms]  <<<  URB 141 coming back  <<< 
         SetupPacket          =
         00000000: 40 0c 01 78 f8 0f 0c 00
       */
      sizew = sizeof (urb_init_141);
      memcpy (dev->windoww, urb_init_141, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x7801, 0x0ff8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb141\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb141 34 end\n");
/*
    [44223 ms]  >>>  URB 142 urb 35 lun going down  >>> 
    00000000: f1 f5 ff f2 f5 80 f3 f5 80 f4 f5 b3
  SetupPacket          =
    00000000: 40 0c 01 f0 f5 00 0c 00
    */
      if (dev->hw->sq930_sensor_ref == Sq930x_creative_live_motion)
	{
	  sizew = sizeof (urb_init_142b);
	  memcpy (dev->windoww, urb_init_142b, sizew);
	}
      else
	{
	  sizew = sizeof (urb_init_142);
	  memcpy (dev->windoww, urb_init_142, sizew);
	}
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0xf001, 0x00f5, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb142\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb142 35 nd\n");
      /*
         [44225 ms]  >>>  URB 143  urb 36 lun going down  >>> 
         data same as urb 142 and urb 35 lun
         SetupPacket          =  40 0c 01 f0 f5 40 0c 00
       */
      if (dev->hw->sq930_sensor_ref == Sq930x_creative_live_motion)
	{
	  sizew = sizeof (urb_init_142b);
	  memcpy (dev->windoww, urb_init_142b, sizew);
	}
      else
	{
	  sizew = sizeof (urb_init_142);
	  memcpy (dev->windoww, urb_init_142, sizew);
	}
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0xf001, 0x40f5, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb143\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb143 36 end\n");
/*
 [44227 ms]  >>>  URB 144 urb 37 lun going down  >>> 
    00000000: f6 f5 00 f7 f5 00 f8 f5 00 f9 f5 00
[44227 ms]  <<<  URB 144 coming back  <<< 
  SetupPacket          =  40 0c 01 fa f5 00 0c 00
 */
      sizew = sizeof (urb_init_144);
      memcpy (dev->windoww, urb_init_144, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0xfa01, 0x00f5, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb144\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb144 37 end\n");
      /*
         [44229 ms]  >>>  URB 145 urb 38 lun going down  >>> 
         00000000: 07 f8 ff 05 f8 80 06 f8 00 07 f8 7f 00 f8 03
         [44229 ms]  <<<  URB 145 coming back  <<< 
         SetupPacket          =  40 0c 01 00 f8 02 0f 00
       */
      sizew = sizeof (urb_init_145);
      memcpy (dev->windoww, urb_init_145, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0001, 0x02f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb145\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb145 38 end\n");
      /*
         [44231 ms]  >>>  URB 146 urb 39 lun going down  >>> 
         00000000: 07 f8 ff 05 f8 4e 06 f8 00 07 f8 7f 00 f8 03
         [44231 ms]  <<<  URB 146 coming back  <<< 
         SetupPacket          =  40 0c 01 00 f8 02 0f 00
       */
      sizew = sizeof (urb_init_146);
      memcpy (dev->windoww, urb_init_146, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0001, 0x02f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb146\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb146 39 end\n");
      /*
         [44232 ms]  >>>  URB 147 urb 40 lun going down  >>> 
         00000000: 07 f8 ff 05 f8 c0 06 f8 48 07 f8 7f 00 f8 03
         [44233 ms]  <<<  URB 147 coming back  <<< 
         SetupPacket          =  40 0c 01 00 f8 02 0f 00
       */
      sizew = sizeof (urb_init_147);
      memcpy (dev->windoww, urb_init_147, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0001, 0x02f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb147\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb147 40 end\n");
      /*
         [44234 ms]  >>>  URB 148 urb 41 lun going down  >>> 
         00000000: 07 f8 ff 05 f8 00 06 f8 00 07 f8 7f 00 f8 03
         [44235 ms]  <<<  URB 148 coming back  <<< 
         SetupPacket          =  40 0c 01 00 f8 02 0f 00
       */
      sizew = sizeof (urb_init_148);
      memcpy (dev->windoww, urb_init_148, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0001, 0x02f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb148\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb148 41 end\n");
      /*
         [44236 ms]  >>>  URB 149 urb 42 lun going down  >>> 
         00000000: 11 f8 10
         [44237 ms]  <<<  URB 149 coming back  <<< 
         SetupPacket          =  40 0c 01 10 f8 03 03 00
       */
      sizew = 0x03;
      dev->windoww[0] = 0x11;
      dev->windoww[1] = 0xf8;
      dev->windoww[2] = 0x10;	/* lu 0x10, lun 0x64 */
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x1001, 0x03f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb149\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb149 42 end\n");
      /*
         [44247 ms]  >>>  URB 150 going down  >>> 
         00000000: 01 22 20 0e 00 a2 02 ee 01 02 00 08 18 12 78 c8
         00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
         [44259 ms]  <<<  URB 150 coming back  <<< 
         SetupPacket          =  40 0c 10 09 04 0a 20 00

         43 out down        n/a     35.591  VENDOR_DEVICE   01 22 20 0e 00 a2 02 f0 
         0000: 01 22 20 0e 00 a2 02 f0 01 02 00 08 18 12 78 c8 
         0010: 07 e1 01 e1 01 3f 01 3f 01 3f 01 05 80 02 e0 01 
         0000: 40 0c 10 3a 04 05 20 00
       */
      usleep (2000);
      sizew = sizeof (urb_init_150);
      /*sizew = sizeof (urb_init_15043); */
      memcpy (dev->windoww, urb_init_150, sizew);
      status =
	/* urb150 */
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0910, 0x0a04, sizew,
			       dev->windoww);
      /* urb 43 lun */
      /* sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x3a10, 0x0504, sizew,
         dev->windoww); */
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb150 43\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb150 43 end\n");
      usleep (2000);
      status = SANE_STATUS_GOOD;

      if (status)
	{
	  DBG (DBG_error, "sq930x_vidcam_init failed : %s\n",
	       sane_strstatus (status));
	  return status;
	}
      break;
    }
  DBG (DBG_proc, "sq930x_vidcam_init: exit\n");
  return status;
}

/* Attach a vidcam to this backend. */
static SANE_Status
attach_vidcam (SANE_String_Const devicename, Sq930x_Vidcam ** devp)
{
  Sq930x_Vidcam *dev;
  int fd;
  SANE_Status status;

  DBG (DBG_proc, "attach_vidcam: %s\n", devicename);

  if (devp)
    *devp = NULL;

  /* Check if we know this device name. */
  for (dev = first_dev; dev; dev = dev->next)
    {
      if (strcmp (dev->sane.name, devicename) == 0)
	{
	  if (devp)
	    {
	      *devp = dev;
	    }
	  DBG (DBG_info, "device is already known\n");
	  return SANE_STATUS_GOOD;
	}
    }

  /* Allocate a new vidcam entry. */
  dev = sq930x_init ();
  if (dev == NULL)
    {
      DBG (DBG_error, "sq930x_init ERROR: not enough memory\n");
      return SANE_STATUS_NO_MEM;
    }

  DBG (DBG_info, "attach_vidcam: opening USB device %s\n", devicename);

  if (sanei_usb_open (devicename, &fd) != 0)
    {
      DBG (DBG_error, "ERROR: attach_vidcam: open failed\n");
      sq930x_free (dev);
      return SANE_STATUS_INVAL;
    }
  /* Fill some scanner specific values. */
  dev->devicename = strdup (devicename);
  dev->fd = fd;

  /* Now, check that it is a vidcam we support. */

  if (sq930x_identify_vidcam (dev) == SANE_FALSE)
    {
      DBG (DBG_error, "ERROR: attach_vidcam: vidcam-identification failed\n");
      sq930x_free (dev);
      return SANE_STATUS_INVAL;
    }

  /* Allocate a buffer memory. */
  status = sq930x_init_2 (dev);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (DBG_error, "sq930x_initi_2, ERROR: not enough memory\n");
      return SANE_STATUS_NO_MEM;
    }

  sq930x_close (dev);

  DBG (DBG_info, "attach_vidcam: opening USB device %s\n", devicename);

  /* Build list of vidcam supported resolutions. */
  DBG (DBG_proc, "attach_vidcam: build resolution list\n");

  if (dev->hw->color_adjust[0].resolution_x != 0)
    {
      int num_entries;
      int i;
      num_entries = 0;

      while (dev->hw->color_adjust[num_entries].resolution_x != 0)
	num_entries++;

      dev->resolutions_list = malloc (sizeof (SANE_Word) * (num_entries + 1));

      if (dev->resolutions_list == NULL)
	{
	  DBG (DBG_error,
	       "ERROR: attach_vidcam: vidcam resolution list failed\n");
	  sq930x_free (dev);
	  return SANE_STATUS_NO_MEM;
	}
      dev->resolutions_list[0] = num_entries;
      DBG (DBG_proc, "attach_vidcam: make color resolution table \n");
      for (i = 0; i < num_entries; i++)
	{
	  dev->resolutions_list[i + 1] =
	    dev->hw->color_adjust[i].resolution_x;
	}
    }
  else
    {
      dev->resolutions_list = NULL;
    }

  /* Set the default options for that vidcam. */
  dev->sane.name = dev->devicename;
  dev->sane.vendor = dev->hw->vendor_name;
  dev->sane.model = dev->hw->product_name;
  dev->sane.type = SANE_I18N ("webcam");

  /* Link the vidcam with the others. */
  dev->next = first_dev;
  first_dev = dev;

  if (devp)
    {
      *devp = dev;
    }

  num_devices++;

  DBG (DBG_proc, "attach_vidcam: exit\n");

  return SANE_STATUS_GOOD;
}

static SANE_Status
attach_one (const char *dev)
{
  DBG (DBG_proc, "attach_one: open \n");
  attach_vidcam (dev, NULL);
  DBG (DBG_proc, "attach_one: exit \n");
  return SANE_STATUS_GOOD;
}

/* Reset the options for that vidcam. */
static void
sq930x_init_options (Sq930x_Vidcam * dev)
{
  int i;

  DBG (DBG_proc, "sq930x_init_options: open\n");

  /* Pre-initialize the options. */
  memset (dev->opt, 0, sizeof (dev->opt));
  memset (dev->val, 0, sizeof (dev->val));

  for (i = 0; i < OPT_NUM_OPTIONS; ++i)
    {
      dev->opt[i].size = sizeof (SANE_Word);
      dev->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
    }
  DBG (DBG_proc,
       "sq930x_init_options: done loop opt_num_options=%d, i=%d \n",
       OPT_NUM_OPTIONS, i);
  /* Number of options. */
  dev->opt[OPT_NUM_OPTS].name = "";
  dev->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
  dev->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
  dev->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
  dev->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
  dev->val[OPT_NUM_OPTS].w = OPT_NUM_OPTIONS;

  /* Mode group */
  dev->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode");
  dev->opt[OPT_MODE_GROUP].desc = "";	/* not valid for a group */
  dev->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
  dev->opt[OPT_MODE_GROUP].cap = 0;
  dev->opt[OPT_MODE_GROUP].size = 0;
  dev->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;

  /* Vidcam supported modes */
  dev->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
  dev->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
  dev->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
  dev->opt[OPT_MODE].type = SANE_TYPE_STRING;
  dev->opt[OPT_MODE].size = max_string_size (scan_mode_list);
  dev->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
  dev->opt[OPT_MODE].constraint.string_list = scan_mode_list;
  dev->val[OPT_MODE].s = (SANE_Char *) strdup ("");	/* will be set later */

  /* X and Y resolution */
  dev->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
  dev->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
  dev->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
  dev->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
  dev->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
  dev->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
  dev->val[OPT_RESOLUTION].w = dev->resolutions_list[1];	/* for different setting use first same resolution */

  /* brightness   */
  dev->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
  dev->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
  dev->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
  dev->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
  dev->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
  dev->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
  dev->opt[OPT_BRIGHTNESS].constraint.range = &brightness_range;
  dev->val[OPT_BRIGHTNESS].w = 0;	/* to get middle value */

  /* Enhancement group */
  dev->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement");
  dev->opt[OPT_ENHANCEMENT_GROUP].desc = "";	/* not valid for a group */
  dev->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
  dev->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED;
  dev->opt[OPT_ENHANCEMENT_GROUP].size = 0;
  dev->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;

  /* Text line option */
  dev->opt[OPT_TEXT].name = "text";
  dev->opt[OPT_TEXT].title = SANE_I18N ("Text");
  dev->opt[OPT_TEXT].desc = SANE_I18N ("Text");
  dev->opt[OPT_TEXT].type = SANE_TYPE_STRING;
  dev->opt[OPT_TEXT].size = max_string_size (text_list);
  dev->opt[OPT_TEXT].cap |= SANE_CAP_INACTIVE;
  dev->opt[OPT_TEXT].constraint_type = SANE_CONSTRAINT_STRING_LIST;
  dev->opt[OPT_TEXT].constraint.string_list = text_list;
  dev->val[OPT_TEXT].s = strdup (text_list[0]);

  /* Decomp option */
  dev->opt[OPT_DECOMP].name = "decomp";
  dev->opt[OPT_DECOMP].title = SANE_I18N ("Decomp");
  dev->opt[OPT_DECOMP].desc = SANE_I18N ("Decomp");
  dev->opt[OPT_DECOMP].type = SANE_TYPE_STRING;
  dev->opt[OPT_DECOMP].size = max_string_size (decomp_list);
  dev->opt[OPT_DECOMP].cap |= SANE_CAP_INACTIVE;
  dev->opt[OPT_DECOMP].constraint_type = SANE_CONSTRAINT_STRING_LIST;
  dev->opt[OPT_DECOMP].constraint.string_list = decomp_list;
  dev->val[OPT_DECOMP].s = strdup (decomp_list[0]);

  /*  Read format option */
  dev->opt[OPT_READ_FORMAT].name = "read_format";
  dev->opt[OPT_READ_FORMAT].title = SANE_I18N ("Read_format");
  dev->opt[OPT_READ_FORMAT].desc = SANE_I18N ("Read_format");
  dev->opt[OPT_READ_FORMAT].type = SANE_TYPE_STRING;
  dev->opt[OPT_READ_FORMAT].size = max_string_size (read_format_list);
  dev->opt[OPT_READ_FORMAT].cap |= SANE_CAP_INACTIVE;
  dev->opt[OPT_READ_FORMAT].constraint_type = SANE_CONSTRAINT_STRING_LIST;
  dev->opt[OPT_READ_FORMAT].constraint.string_list = read_format_list;
  dev->val[OPT_READ_FORMAT].s = strdup (read_format_list[0]);

  /* red level calibration manual correction */
  dev->opt[OPT_WHITE_LEVEL_R].name = SANE_NAME_WHITE_LEVEL_R;
  dev->opt[OPT_WHITE_LEVEL_R].title = SANE_TITLE_WHITE_LEVEL_R;
  dev->opt[OPT_WHITE_LEVEL_R].desc = SANE_DESC_WHITE_LEVEL_R;
  dev->opt[OPT_WHITE_LEVEL_R].type = SANE_TYPE_INT;
  dev->opt[OPT_WHITE_LEVEL_R].unit = SANE_UNIT_NONE;
  dev->opt[OPT_WHITE_LEVEL_R].constraint_type = SANE_CONSTRAINT_RANGE;
  dev->opt[OPT_WHITE_LEVEL_R].constraint.range = &red_level_range;
  dev->val[OPT_WHITE_LEVEL_R].w = 00;	/* to get middle value */

  /* green level calibration manual correction */
  dev->opt[OPT_WHITE_LEVEL_G].name = SANE_NAME_WHITE_LEVEL_G;
  dev->opt[OPT_WHITE_LEVEL_G].title = SANE_TITLE_WHITE_LEVEL_G;
  dev->opt[OPT_WHITE_LEVEL_G].desc = SANE_DESC_WHITE_LEVEL_G;
  dev->opt[OPT_WHITE_LEVEL_G].type = SANE_TYPE_INT;
  dev->opt[OPT_WHITE_LEVEL_G].unit = SANE_UNIT_NONE;
  dev->opt[OPT_WHITE_LEVEL_G].constraint_type = SANE_CONSTRAINT_RANGE;
  dev->opt[OPT_WHITE_LEVEL_G].constraint.range = &green_level_range;
  dev->val[OPT_WHITE_LEVEL_G].w = 00;	/* to get middle value */

  /* blue level calibration manual correction */
  dev->opt[OPT_WHITE_LEVEL_B].name = SANE_NAME_WHITE_LEVEL_B;
  dev->opt[OPT_WHITE_LEVEL_B].title = SANE_TITLE_WHITE_LEVEL_B;
  dev->opt[OPT_WHITE_LEVEL_B].desc = SANE_DESC_WHITE_LEVEL_B;
  dev->opt[OPT_WHITE_LEVEL_B].type = SANE_TYPE_INT;
  dev->opt[OPT_WHITE_LEVEL_B].unit = SANE_UNIT_NONE;
  dev->opt[OPT_WHITE_LEVEL_B].constraint_type = SANE_CONSTRAINT_RANGE;
  dev->opt[OPT_WHITE_LEVEL_B].constraint.range = &blue_level_range;
  dev->val[OPT_WHITE_LEVEL_B].w = 00;	/* to get middle value */

  DBG (DBG_proc, "sq930x_init_options: after blue level\n");

  /* Lastly, set the default scan mode. This might change some
   * values previously set here. */

  sane_control_option (dev, OPT_MODE, SANE_ACTION_SET_VALUE,
		       (SANE_String_Const *) scan_mode_list[0], NULL);
  DBG (DBG_proc, "sq930x_init_options: exit\n");
}

/* Read the image from the vidcam and fill the temporary buffer with it. */
static SANE_Status
sq930x_fill_image (Sq930x_Vidcam * dev)
{
  SANE_Status status;
  size_t size;
  size_t bulk_size_read;
  size_t sizer;
  size_t sizew;
  size_t sizei;
  size_t sizeo;
  size_t sizeb;
  int read_timeout;
  size_t x;

  DBG (DBG_proc, "sq930x_fill_image: enter\n");

  sizew = dev->windoww_size;
  sizer = dev->windowr_size;

  memset (dev->windoww, 0, sizew);
  memset (dev->windowr, 0, sizer);

/* clear screen each time with new image */

  sizeb = dev->buffer_size;
  sizei = dev->image_size;
  sizeo = dev->output_size;

  memset (dev->buffer, 0, sizeb);
  memset (dev->output, 0, sizeo);
  memset (dev->image, 0, sizei);

  switch (dev->hw->sq930_sensor_ref)
    {
    case Sq930x_trust_3500t:
    case Sq930x_MI360:
    case Sq930x_sweex_motion_tracking:
    case Sq930x_creative_ultra_notebook:
    case Sq930x_creative_live_motion:
      /*
         [47525 ms]  >>>  URB 152 going down  >>> 
         00000000: 03 00 12 93 0b f6 c9 00
         SetupPacket          =
         00000000: c0 0c 1f 00 00 00 08 00
       */
      sizew = 0x00;
      status = sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0011, 0x0000, sizew,	/* 0x0011 instead of 0x000f  write instead of read */
				      dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb152 44\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb152 44 end\n");
      /*
         [47530 ms]  >>>  URB 153 going down  >>> 
         00000000: 00 00 03 bc 8b
         SetupPacket          =
         00000000: 40 0c 1d 00 00 00 05 00
         [48529 ms]  >>>  URB 154 going down  >>> 
       */
      sizew = 0x03;
      dev->windoww[0] = 0x11;
      dev->windoww[1] = 0xf8;
      dev->windoww[2] = 0x10;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x1001, 0x03f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb153\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb153 45 end\n");
      /*
         [44247 ms]  >>>  URB 150  46 going down  >>> 
         00000000: 01 22 20 0e 00 a2 02 ee 01 02 00 08 18 12 78 c8
         00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
         [44259 ms]  <<<  URB 150 coming back  <<< 
         SetupPacket          =  40 0c 10 09 04 0a 20 00
       */
      if (dev->scan_mode == SQ930X_COLOR_RGB)
	{
	  sizew = sizeof (urb_init_150);
	  memcpy (dev->windoww, urb_init_150, sizew);
	  status =
	    sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0910, 0x0a04, sizew,
				   dev->windoww);
	  if (status != SANE_STATUS_GOOD)
	    {
	      DBG (DBG_proc, "sq930x_vidcam_init: urb150\n");
	      return status;
	    }
	  DBG (DBG_proc, "sq930x_vidcam_init: urb150 46 end\n");
	}
      if ((dev->scan_mode != SQ930X_COLOR_RGB)
	  || (dev->scan_mode != SQ930X_COLOR_RAW))
	{
	  sizew = sizeof (urb_init_150a);
	  memcpy (dev->windoww, urb_init_150a, sizew);
	  status =
	    sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0910, 0x0a04, sizew,
				   dev->windoww);
	  if (status != SANE_STATUS_GOOD)
	    {
	      DBG (DBG_proc, "sq930x_vidcam_init: urb150a\n");
	      return status;
	    }
	  DBG (DBG_proc, "sq930x_vidcam_init: urb150 46 end\n");
	}

/* for rgb?? */

/*if (dev->scan_mode == SQ930X_COLOR_RGB)
    {
 
      sizew = 0x00;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0011, 0x0000, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb153\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb153 47 end\n");
      }
 */
      sizew = 0x03;
      dev->windoww[0] = 0x11;
      dev->windoww[1] = 0xf8;
      dev->windoww[2] = 0x30;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x1001, 0x03f8, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb153\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb153 48 end\n");

      sizew = sizeof (urb_init_150);
      memcpy (dev->windoww, urb_init_150, sizew);
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x0910, 0x0a04, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb150 49\n");

	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb150 49 end\n");

      sizew = 0x05;
      dev->windoww[0] = 0x01;
      dev->windoww[1] = 0xd0;
      dev->windoww[2] = 0x02;
      dev->windoww[3] = 0x6f;
      dev->windoww[4] = 0x40;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x001d, 0x0000, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb153 50\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb153 50 end\n");

      sizew = 0x05;
      dev->windoww[0] = 0x02;
      dev->windoww[1] = 0x30;
      dev->windoww[2] = 0x02;
      dev->windoww[3] = 0x6f;
      dev->windoww[4] = 0x40;
      status =
	sanei_usb_control_msg (dev->fd, 0x40, 0x0c, 0x001d, 0x0000, sizew,
			       dev->windoww);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_proc, "sq930x_vidcam_init: urb153 51\n");
	  return status;
	}
      DBG (DBG_proc, "sq930x_vidcam_init: urb153 51 end\n");
      break;
    }
  /* Try to read the maximum number of bytes. */
  size = 1024 * 1024;

  /* Do the transfer */

  DBG (DBG_proc,
       "sq930x_fill_image: dev->real_bytes_left: 0x%lx size: 0x%lx\n",
       (unsigned long) (size_t) dev->real_bytes_left,
       (unsigned long) (size_t) size);
  switch (dev->hw->sq930_sensor_ref)
    {
    case Sq930x_trust_3500t:
    case Sq930x_MI360:
    case Sq930x_sweex_motion_tracking:
    case Sq930x_creative_ultra_notebook:
    case Sq930x_creative_live_motion:
      status = sanei_usb_read_bulk (dev->fd, dev->buffer, &size);
      if (status != SANE_STATUS_GOOD)
	{
	  return status;
	  DBG (DBG_proc, "bulk read  error");
	}
      memcpy (dev->image, dev->buffer, size);

      dev->image_begin = 0;
      dev->image_end = size;
      x = size / 0x280;		/* 640 pixels */
      DBG (DBG_info,
	   "sq930x_fill_image: raw image size (read) = 0x%lx bytes (bpl=0x%lx) x=%1d\n",
	   (unsigned long) size,
	   (unsigned long) dev->params.bytes_per_line, (unsigned long) x);
      break;
    }

  DBG (DBG_proc, "sq930x_fill_image: exit\n");
  return (SANE_STATUS_GOOD);	/* unreachable */
}

/**********************************************************************
*
* The add_text routine and font_6x11.h file are taken from the (GPLed) 
* webcam.c file, part of xawtv,   (c) 1998-2002 Gerd Knorr.
* add_text was slightly modified for the pencam2 program.
* sq930x_add_text was taken from the pencam2 program and changed on
* some points
*
*********************************************************************/

#define MSG_MAXLEN   45
#define CHAR_HEIGHT  11
#define CHAR_WIDTH   6
#define CHAR_START   4

static SANE_Status
sq930x_add_text (Sq930x_Vidcam * dev, SANE_Byte * image, int width,
		 int height, char *txt)
{
  SANE_Status status;
  time_t t;
  struct tm *tm;
  char line[MSG_MAXLEN + 1];
  SANE_Byte *ptr;
  int i, x, y, f, len;
  char fmtstring[25] = " %Y-%m-%d %H:%M:%S";
  char fmttxt[46];

  DBG (DBG_proc, "sq930x_add_text: enter\n");
  time (&t);
  tm = localtime (&t);
  if (strlen (txt) > (MSG_MAXLEN - 23))
    strncpy (fmttxt, txt, (MSG_MAXLEN - 23));
  else
    strcpy (fmttxt, txt);
  strcat (fmttxt, fmtstring);

  len = strftime (line, MSG_MAXLEN, fmttxt, tm);

  if (dev->scan_mode != SQ930X_COLOR_RAW)
    {
      for (y = 0; y < CHAR_HEIGHT; y++)
	{
	  ptr = image + 3 * width * (height - CHAR_HEIGHT - 2 + y) + 12;

	  for (x = 0; x < len; x++)
	    {
	      f = fontdata[line[x] * CHAR_HEIGHT + y];
	      for (i = CHAR_WIDTH - 1; i >= 0; i--)
		{
		  if (f & (CHAR_START << i))
		    {
		      ptr[0] = 255;
		      ptr[1] = 255;
		      ptr[2] = 255;
		    }
		  ptr += 3;
		}		/* for i */
	    }			/* for x */
	}			/* for y */
    }
  else
    {
      for (y = 0; y < CHAR_HEIGHT; y++)
	{
	  ptr = image + width * (height - CHAR_HEIGHT - 2 + y) + 12;

	  for (x = 0; x < len; x++)
	    {
	      f = fontdata[line[x] * CHAR_HEIGHT + y];
	      for (i = CHAR_WIDTH - 1; i >= 0; i--)
		{
		  if (f & (CHAR_START << i))
		    {
		      ptr[0] = 255;
		    }
		  ptr += 1;
		}		/* for i */
	    }			/* for x */
	}			/* for y */

    }

  DBG (DBG_proc, "sq930x_add_text: exit vw=%d, vh=%d\n", width, height);
  status = (SANE_STATUS_GOOD);
  return status;

}				/*  end of add_text  */

/* **************************  Video Decoding  *********************  */
#define AD(x, y, vw) (((y)*(vw)+(x))*3)
#define ADI(x, y, vw) (((y)*(vw)+(x)))

static SANE_Status
sq930x_bayer_unshuffle (Sq930x_Vidcam * dev, SANE_Byte * buf, size_t * size)
{
  SANE_Status status;
  long int x, y;
  long int i = 0;
  int RED, GREEN, BLUE;
  int vw = dev->x_resolution;
  int w = dev->x_resolution;
  int vh = dev->y_resolution;
  SANE_Byte p = 0;
  int colour = 0, bayer = 0;
  int bright_red;
  int bright_green;
  int bright_blue;
  int bright_raw;
  long int count;
  size_t head;
  int tile;
  size_t size_offset;

  RED = dev->red_s;
  GREEN = dev->green_s;
  BLUE = dev->blue_s;

  DBG (DBG_proc, "sq930x_bayer_unshuffle: enter\n");

  size = 0x80;			/* show 80 bytes header + begin */
  hexdump (DBG_proc,
	   "sq930x_bayer_unshuffle show 0x80 bytes image header 1st line",
	   dev->image, size);

  size = 0x80;			/* show 80 bytes header 2nd line */
  size_offset = 0x280;
  hexdump (DBG_proc,
	   "sq930x_bayer_unshuffle show 0x80 bytes image header 2nd line",
	   (dev->image + size_offset), size);

  if (dev->scan_mode == SQ930X_COLOR_RAW)
    {
      DBG (DBG_info, "bayer unshuffle: raw mode\n");
    }

/* image comment
 * first 2 bytes seems header fc d4
 * after that black is a2 80 0a 28 00 (5 bytes long?)
 */

/* remove 2 (1) bytes header from file , no green colour correction yet*/

  if (dev->scan_mode == SQ930X_COLOR_RGB)
    {
      size = vw * vh;

      for (i = 0; i < size; i++)
	*(dev->image + i) = *(dev->image + i + 0x01);
    }

  if (dev->scan_mode == SQ930X_COLOR)
    {
      SANE_Status status;

/* just copy gray to 3 colour values */
      size = vw * vh;
      for (i = 0; i < size; i++)
	{
	  y = i * 3;
	  *(dev->output + y) = *(dev->image + i);
	  *(dev->output + (y + 1)) = *(dev->image + i);
	  *(dev->output + (y + 2)) = *(dev->image + i);
	}
    }

  if (dev->scan_mode == SQ930X_COLOR_RGB)
    {
      DBG (DBG_proc,
	   "sq930x_bayer_unshuffle: color read RED=%d, GREEN=%d, BLUE=%d\n",
	   RED, GREEN, BLUE);

	/******  bayer demosaic  ******/
      for (y = 1; y < (vh - 1); y++)
	{
	  for (x = 1; x < (vw - 1); x++)
	    {			/* work out pixel type */
	      if (y & 1)
		bayer = 0;	/*      Green pixel  y=1 */
	      else
		bayer = 2;	/*      Blue pixel y=2 */
	      if (!(x & 1))	/*      Red pixel  x=2, y=1, Green x = 2, y=2 */
		bayer++;
	      switch (bayer)
		{
		case 0:	/* green pixel. blue leftright, red topbottom */
		  (dev->output[AD (x, y, vw) + BLUE]) =
		    (((int) (dev->image[ADI (x - 1, y, vw)]) +
		      (int) (dev->image[ADI (x + 1, y, vw)])) >> 1);
		  (dev->output[AD (x, y, vw) + RED]) =
		    (((int) (dev->image[ADI (x, y - 1, vw)]) +
		      (int) (dev->image[ADI (x, y + 1, vw)])) >> 1);
		  (dev->output[AD (x, y, vw) + GREEN]) =
		    ((int) (dev->image[ADI (x, y, vw)]));
		  break;

		case 1:	/* blue pixel. green lrtb, red diagonals */
		  (dev->output[AD (x, y, vw) + GREEN]) =
		    (((int) (dev->image[ADI (x - 1, y, vw)]) +
		      (int) (dev->image[ADI (x + 1, y, vw)]) +
		      (int) (dev->image[ADI (x, y - 1, vw)]) +
		      (int) (dev->image[ADI (x, y + 1, vw)])) >> 2);
		  (dev->output[AD (x, y, vw) + RED]) =
		    (((int) (dev->image[ADI (x - 1, y - 1, vw)]) +
		      (int) (dev->image[ADI (x - 1, y + 1, vw)]) +
		      (int) (dev->image[ADI (x + 1, y - 1, vw)]) +
		      (int) (dev->image[ADI (x + 1, y + 1, vw)])) >> 2);
		  (dev->output[AD (x, y, vw) + BLUE]) =
		    ((int) (dev->image[ADI (x, y, vw)]));
		  break;

		case 2:	/* red pixel. green lrtb, blue diagonals */
		  (dev->output[AD (x, y, vw) + GREEN]) =
		    (((int) (dev->image[ADI (x - 1, y, vw)]) +
		      (int) (dev->image[ADI (x + 1, y, vw)]) +
		      (int) (dev->image[ADI (x, y - 1, vw)]) +
		      (int) (dev->image[ADI (x, y + 1, vw)])) >> 2);
		  (dev->output[AD (x, y, vw) + BLUE]) =
		    (((int) (dev->image[ADI (x - 1, y - 1, vw)]) +
		      (int) (dev->image[ADI (x + 1, y - 1, vw)]) +
		      (int) (dev->image[ADI (x - 1, y + 1, vw)]) +
		      (int) (dev->image[ADI (x + 1, y + 1, vw)])) >> 2);
		  (dev->output[AD (x, y, vw) + RED]) =
		    ((int) (dev->image[ADI (x, y, vw)]));
		  break;

		case 3:	/* green pixel. red lr, blue tb */
		  (dev->output[AD (x, y, vw) + RED]) =
		    (((int) (dev->image[ADI (x - 1, y, vw)]) +
		      (int) (dev->image[ADI (x + 1, y, vw)])) >> 1);
		  (dev->output[AD (x, y, vw) + BLUE]) =
		    (((int) (dev->image[ADI (x, y - 1, vw)]) +
		      (int) (dev->image[ADI (x, y + 1, vw)])) >> 1);
		  (dev->output[AD (x, y, vw) + GREEN]) =
		    ((int) (dev->image[ADI (x, y, vw)]));
		  break;
		}		/* switch */
	    }			/* for x */
	}			/* for y  - end demosaic  */

      size = 0x280;		/* show 0x280 bytes header 1st line */
      hexdump (DBG_proc,
	       "sq930x_bayer_unshuffle show 0x280 bytes header 1st line",
	       dev->output, size);
      size = 0x280;		/* show 0x280 bytes header 4th line */
      size_offset = 0x780;
      hexdump (DBG_proc,
	       "sq930x_bayer_unshuffle show 0x280 bytes image header 4th line",
	       (dev->output + size_offset), size);

    }				/* no bayer demosaic */

  if (dev->scan_mode == SQ930X_COLOR)
    {
      /* fix top and bottom row, left and right side */
      i = vw * 3;
      memcpy (dev->output, (dev->output + i), i);
      memcpy ((dev->output + (vh * i)), (dev->output + ((vh - 1) * i)), i);

      for (y = 0; y < vh; y++)
	{
	  i = y * vw * 3;
	  memcpy ((dev->output + i), (dev->output + i + 3), 3);
	  memcpy ((dev->output + i + (vw * 3)),
		  (dev->output + i + (vw - 1) * 3), 3);
	}
    }

  /* brightness adjustment */

  if (dev->scan_mode != SQ930X_COLOR_RAW)
    {

      count = vw * vh * 3;

      bright_red =
	(dev->val[OPT_BRIGHTNESS].w) + (dev->val[OPT_WHITE_LEVEL_R].w);
      bright_green =
	(dev->val[OPT_BRIGHTNESS].w) + (dev->val[OPT_WHITE_LEVEL_G].w);
      bright_blue =
	(dev->val[OPT_BRIGHTNESS].w) + (dev->val[OPT_WHITE_LEVEL_B].w);

      for (x = 0; x < count; x++)
	{
	  if ((*(dev->output + x) + bright_red) >= 255)
	    *(dev->image + x) = 255;

	  else if ((*(dev->output + x) + bright_red) <= 0)
	    *(dev->image + x) = 0;
	  else
	    *(dev->image + x) = (*(dev->output + x) + bright_red);

	  x++;

	  if ((*(dev->output + x) + bright_green) >= 255)
	    *(dev->image + x) = 255;

	  else if ((*(dev->output + x) + bright_green) <= 0)
	    *(dev->image + x) = 0;
	  else
	    *(dev->image + x) = (*(dev->output + x) + bright_green);

	  x++;

	  if ((*(dev->output + x) + bright_blue) >= 255)
	    *(dev->image + x) = 255;

	  else if ((*(dev->output + x) + bright_blue) <= 0)
	    *(dev->image + x) = 0;
	  else
	    *(dev->image + x) = (*(dev->output + x) + bright_blue);
	}

      dev->image_end = sizeof (dev->image);
      dev->image_begin = 0;
    }
  else
    {
      size = vw * vh;

      bright_raw = (dev->val[OPT_BRIGHTNESS].w);

      for (x = 0; x < size; x++)
	{
	  if ((*(dev->image + x) + bright_raw) >= 255)
	    *(dev->image + x) = 255;

	  else if ((*(dev->image + x) + bright_raw) <= 0)
	    *(dev->image + x) = 0;
	  else
	    *(dev->image + x) = (*(dev->image + x) + bright_raw);
	}
      dev->image_end = sizeof (dev->image);
      dev->image_begin = 0;
    }

/**********************************************************************
*
* The add_text routine and font_6x11.h file are taken from the (GPLed) 
* webcam.c file, part of xawtv,   (c) 1998-2002 Gerd Knorr.
* add_text was slightly modified for this program.
*
*********************************************************************/

  if (dev->text_line == 0x01)
    {
      strcpy (dev->picmsg_ps, "SQ930xcam ");

      status = sq930x_add_text (dev, dev->image, vw, vh, dev->picmsg_ps);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_info, "sq930x_bayer_unshuffle status NOK\n");
	  return (status);
	}
    }

  DBG (DBG_proc, "sq930x_bayer_unshuffle: exit vw=%d, vh=%d\n", vw, vh);
  status = (SANE_STATUS_GOOD);
  return status;
}

static SANE_Status
sq930x_jpeg (Sq930x_Vidcam * dev, SANE_Byte * buf, size_t * size)
{
  SANE_Status status;
  int x, y;
  int i = 0;
  /*int RED, GREEN, BLUE; */
  int w = dev->cwidth;
  int vw = dev->x_resolution;
  int vh = dev->y_resolution;
  SANE_Byte p = 0;
  int colour = 0, bayer = 0;
  int bright_red;
  int bright_green;
  int bright_blue;
  int count;

  /*RED = dev->red_s;
     GREEN = dev->green_s;
     BLUE = dev->blue_s;
   */
  DBG (DBG_proc, "sq930x_jpeg: enter\n");

/* image comment
 * first 2 bytes seems header fc d4  (jpeg header)
 * after that black is a2 80 0a 28 00 (5 bytes long?)
 */
  size = 0x80;			/* show 80 bytes header + begin */
  hexdump (DBG_proc, "sq930x_bayer_unshuffle show 0x80 bytes header",
	   dev->image, size);

/* remove 2 bytes header from file */
  size = vw * vh;

  for (i = 0; i < size; i++)
    *(dev->image + i) = *(dev->image + i + 0x02);

/* memcopy from image to image, not correct yet, just for test */
  size = vw * vh * 3;
  for (i = 0; i < size; i++)
    *(dev->image + i) = *(dev->image + i);

/* insert add text routine                 */
/**********************************************************************
*
* The add_text routine and font_6x11.h file are taken from the (GPLed) 
* webcam.c file, part of xawtv,   (c) 1998-2002 Gerd Knorr.
* add_text was slightly modified for this program.
*
*********************************************************************/

  if (dev->text_line == 0x01)
    {
      strcpy (dev->picmsg_ps, "SQ930xcam ");

      status = sq930x_add_text (dev, dev->image, vw, vh, dev->picmsg_ps);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_info, "sq930x_bayer_unshuffle status NOK\n");
	  return (status);
	}
    }

  DBG (DBG_proc, "sq930x_bayer_unshuffle: exit vw=%d, vh=%d\n", vw, vh);
  status = (SANE_STATUS_GOOD);
  return status;
}

/* Sane entry points */

SANE_Status
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
{
  FILE *fp;
  char line[PATH_MAX];
  size_t len;

  num_devices = 0;
  devlist = NULL;
  first_dev = NULL;

  DBG_INIT ();

  DBG (DBG_sane_init, "sane_init\n");

  authorize = authorize;	/* silence gcc */

  DBG (DBG_error, "This is sane-sq930x version %d.%d-%d\n", V_MAJOR,
       V_MINOR, BUILD);
  DBG (DBG_error, "(C) 2006-2008 by Gerard Klaver\n");

  if (version_code)
    {
      *version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, BUILD);
    }

  DBG (DBG_proc, "sane_init: authorize %s null\n", authorize ? "!=" : "==");

  sanei_usb_init ();

  fp = sanei_config_open (SQ930X_CONFIG_FILE);
  if (!fp)
    {
      /* No default vidcam? */
      DBG (DBG_warning, "configuration file not found (%s)\n",
	   SQ930X_CONFIG_FILE);

      return SANE_STATUS_GOOD;
    }

  while (sanei_config_read (line, sizeof (line), fp))
    {
      SANE_Word vendor;
      SANE_Word product;

      if (line[0] == '#')	/* ignore line comments */
	continue;
      len = strlen (line);

      if (!len)
	continue;		/* ignore empty lines */
      if (sscanf (line, "usb %i %i", &vendor, &product) == 2)
	{

	  sanei_usb_attach_matching_devices (line, attach_one);
	}
      else
	{
	  /* Garbage. Ignore. */
	  DBG (DBG_warning, "bad configuration line: \"%s\" - ignoring.\n",
	       line);
	}
    }

  fclose (fp);

  DBG (DBG_proc, "sane_init: leave\n");

  return SANE_STATUS_GOOD;
}

SANE_Status
sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
{
  Sq930x_Vidcam *dev;
  int i;

  DBG (DBG_proc, "sane_get_devices: enter\n");

  local_only = local_only;	/* silence gcc */

  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; i < num_devices; dev = dev->next)
    devlist[i++] = &dev->sane;
  devlist[i++] = 0;

  *device_list = devlist;

  DBG (DBG_proc, "sane_get_devices: exit\n");

  return SANE_STATUS_GOOD;
}

SANE_Status
sane_open (SANE_String_Const devicename, SANE_Handle * handle)
{
  Sq930x_Vidcam *dev;
  SANE_Status status;

  DBG (DBG_proc, "sane_open: enter\n");

  /* search for devicename */
  if (devicename[0])
    {
      DBG (DBG_info, "sane_open: devicename=%s\n", devicename);

      for (dev = first_dev; dev; dev = dev->next)
	{
	  if (strcmp (dev->sane.name, devicename) == 0)
	    {
	      break;
	    }
	}

      if (!dev)
	{
	  status = attach_vidcam (devicename, &dev);
	  if (status != SANE_STATUS_GOOD)
	    {
	      return status;
	    }
	}
    }
  else
    {
      DBG (DBG_sane_info, "sane_open: no devicename, opening first device\n");
      dev = first_dev;		/* empty devicename -> use first device */
    }

  if (!dev)
    {
      DBG (DBG_error, "No vidcam found\n");

      return SANE_STATUS_INVAL;
    }

  sq930x_init_options (dev);

  *handle = dev;

  DBG (DBG_proc, "sane_open: exit\n");

  return SANE_STATUS_GOOD;
}

const SANE_Option_Descriptor *
sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
{
  Sq930x_Vidcam *dev = handle;

  DBG (DBG_proc, "sane_get_option_descriptor: enter, option %d\n", option);

  if ((unsigned) option >= OPT_NUM_OPTIONS)
    {
      return NULL;
    }

  DBG (DBG_proc, "sane_get_option_descriptor: exit\n");

  return dev->opt + option;
}

SANE_Status
sane_control_option (SANE_Handle handle, SANE_Int option,
		     SANE_Action action, void *val, SANE_Int * info)
{
  Sq930x_Vidcam *dev = handle;
  SANE_Status status;
  SANE_Word cap;

  DBG (DBG_proc, "sane_control_option: enter, option %d, action %d\n",
       option, action);

  if (info)
    {
      *info = 0;
    }

  if (dev->scanning)
    {
      return SANE_STATUS_DEVICE_BUSY;
    }

  if (option < 0 || option >= OPT_NUM_OPTIONS)
    {
      return SANE_STATUS_INVAL;
    }

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

  if (action == SANE_ACTION_GET_VALUE)
    {

      switch (option)
	{
	  /* word options */
	case OPT_NUM_OPTS:
	case OPT_RESOLUTION:
	case OPT_BRIGHTNESS:
	case OPT_WHITE_LEVEL_R:
	case OPT_WHITE_LEVEL_G:
	case OPT_WHITE_LEVEL_B:
	  *(SANE_Word *) val = dev->val[option].w;
	  return SANE_STATUS_GOOD;
	case OPT_MODE:
	case OPT_TEXT:
	case OPT_DECOMP:
	case OPT_READ_FORMAT:
	  strcpy (val, dev->val[option].s);
	  return SANE_STATUS_GOOD;
	default:
	  return SANE_STATUS_INVAL;
	}
    }
  else if (action == SANE_ACTION_SET_VALUE)
    {

      if (!SANE_OPTION_IS_SETTABLE (cap))
	{
	  DBG (DBG_error, "could not set option, not settable\n");
	  return SANE_STATUS_INVAL;
	}

      status = sanei_constrain_value (dev->opt + option, val, info);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_error, "could not set option, invalid value\n");
	  return status;
	}

      switch (option)
	{

	  /* Numeric side-effect options */
	case OPT_RESOLUTION:
	case OPT_BRIGHTNESS:
	case OPT_WHITE_LEVEL_R:
	case OPT_WHITE_LEVEL_G:
	case OPT_WHITE_LEVEL_B:
	  if (info)
	    {
	      *info |= SANE_INFO_RELOAD_PARAMS;
	    }
	  dev->val[option].w = *(SANE_Word *) val;
	  return SANE_STATUS_GOOD;

	  /* String side-effect options */
	case OPT_TEXT:
	  free (dev->val[option].s);
	  dev->val[option].s = (SANE_String) strdup (val);
	  return SANE_STATUS_GOOD;
	case OPT_DECOMP:
	  free (dev->val[option].s);
	  dev->val[option].s = (SANE_String) strdup (val);
	  return SANE_STATUS_GOOD;
	case OPT_READ_FORMAT:
	  free (dev->val[option].s);
	  dev->val[option].s = (SANE_String) strdup (val);
	  return SANE_STATUS_GOOD;
	  /* String side-effect options */
	case OPT_MODE:
	  if (strcmp (dev->val[option].s, val) == 0)
	    return SANE_STATUS_GOOD;

	  free (dev->val[OPT_MODE].s);
	  dev->val[OPT_MODE].s = (SANE_Char *) strdup (val);

	  dev->opt[OPT_TEXT].cap |= SANE_CAP_INACTIVE;
	  dev->opt[OPT_DECOMP].cap |= SANE_CAP_INACTIVE;
	  dev->opt[OPT_READ_FORMAT].cap |= SANE_CAP_INACTIVE;
	  dev->opt[OPT_WHITE_LEVEL_R].cap |= SANE_CAP_INACTIVE;
	  dev->opt[OPT_WHITE_LEVEL_G].cap |= SANE_CAP_INACTIVE;
	  dev->opt[OPT_WHITE_LEVEL_B].cap |= SANE_CAP_INACTIVE;

	  if (strcmp (dev->val[OPT_MODE].s, COLOR_RAW_STR) == 0)
	    {
	      dev->scan_mode = SQ930X_COLOR_RAW;
	      dev->depth = 8;
	      dev->opt[OPT_TEXT].cap &= ~SANE_CAP_INACTIVE;
	      dev->opt[OPT_DECOMP].cap &= ~SANE_CAP_INACTIVE;
	      dev->opt[OPT_READ_FORMAT].cap &= ~SANE_CAP_INACTIVE;
	    }
	  else if (strcmp (dev->val[OPT_MODE].s, COLOR_RGB_STR) == 0)
	    {
	      dev->scan_mode = SQ930X_COLOR_RGB;
	      dev->depth = 8;
	      dev->opt[OPT_TEXT].cap &= ~SANE_CAP_INACTIVE;
	      dev->opt[OPT_DECOMP].cap &= ~SANE_CAP_INACTIVE;
	      dev->opt[OPT_READ_FORMAT].cap &= ~SANE_CAP_INACTIVE;
	      dev->opt[OPT_WHITE_LEVEL_R].cap &= ~SANE_CAP_INACTIVE;
	      dev->opt[OPT_WHITE_LEVEL_G].cap &= ~SANE_CAP_INACTIVE;
	      dev->opt[OPT_WHITE_LEVEL_B].cap &= ~SANE_CAP_INACTIVE;
	    }
	  else if (strcmp (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR)
		   == 0)
	    {
	      dev->scan_mode = SQ930X_COLOR;
	      dev->depth = 8;
	      dev->opt[OPT_TEXT].cap &= ~SANE_CAP_INACTIVE;
	      dev->opt[OPT_DECOMP].cap &= ~SANE_CAP_INACTIVE;
	      dev->opt[OPT_READ_FORMAT].cap &= ~SANE_CAP_INACTIVE;
	      dev->opt[OPT_WHITE_LEVEL_R].cap &= ~SANE_CAP_INACTIVE;
	      dev->opt[OPT_WHITE_LEVEL_G].cap &= ~SANE_CAP_INACTIVE;
	      dev->opt[OPT_WHITE_LEVEL_B].cap &= ~SANE_CAP_INACTIVE;
	    }

	  /* The SQ930X supports only a handful of resolution. */
	  /* This the default resolution range for the SQ930X */

	  if (dev->resolutions_list != NULL)
	    {
	      int i;

	      dev->opt[OPT_RESOLUTION].constraint_type =
		SANE_CONSTRAINT_WORD_LIST;
	      dev->opt[OPT_RESOLUTION].constraint.word_list =
		dev->resolutions_list;

	      /* If the resolution isn't in the list, set a default. */
	      for (i = 1; i <= dev->resolutions_list[0]; i++)
		{
		  if (dev->resolutions_list[i] >= dev->val[OPT_RESOLUTION].w)
		    break;
		}
	      if (i > dev->resolutions_list[0])
		{
		  /* Too big. Take lowest. */
		  dev->val[OPT_RESOLUTION].w = dev->resolutions_list[1];
		}
	      else
		{
		  /* Take immediate superioir value. */
		  dev->val[OPT_RESOLUTION].w = dev->resolutions_list[i];
		}
	    }

	  /* String side-effect options */

	  if (info)
	    {
	      *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
	    }
	  return SANE_STATUS_GOOD;
	default:
	  return SANE_STATUS_INVAL;
	}
    }

  DBG (DBG_proc, "sane_control_option: exit, bad\n");

  return SANE_STATUS_UNSUPPORTED;
}

SANE_Status
sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
{
  Sq930x_Vidcam *dev = handle;
  int i;

  DBG (DBG_proc, "sane_get_parameters: enter\n");

  if (!(dev->scanning))
    {
      dev->x_resolution = dev->val[OPT_RESOLUTION].w;
      /* Prepare the parameters for the caller. */
      memset (&dev->params, 0, sizeof (SANE_Parameters));

      dev->params.last_frame = SANE_TRUE;

      switch (dev->scan_mode)
	{
	case SQ930X_COLOR_RAW:
	  dev->bytes_pixel = 1;
	  i = get_string_list_index (text_list, dev->val[OPT_TEXT].s);
	  dev->text_line = text_val[i];
	  i = get_string_list_index (decomp_list, dev->val[OPT_DECOMP].s);
	  dev->decomp_alg = decomp_val[i];
	  i =
	    get_string_list_index (read_format_list,
				   dev->val[OPT_READ_FORMAT].s);
	  dev->read_format = read_format_val[i];
	  dev->params.format = SANE_FRAME_GRAY;
	  break;
	case SQ930X_COLOR_RGB:
	case SQ930X_COLOR:
	  dev->bytes_pixel = 3;
	  i = get_string_list_index (text_list, dev->val[OPT_TEXT].s);
	  dev->text_line = text_val[i];
	  i = get_string_list_index (decomp_list, dev->val[OPT_DECOMP].s);
	  dev->decomp_alg = decomp_val[i];
	  i =
	    get_string_list_index (read_format_list,
				   dev->val[OPT_READ_FORMAT].s);
	  dev->read_format = read_format_val[i];
	  dev->params.format = SANE_FRAME_RGB;
	  break;
	}
      dev->params.pixels_per_line = dev->x_resolution;
      dev->params.bytes_per_line =
	dev->params.pixels_per_line * dev->bytes_pixel;
      dev->params.depth = 8;
      if (dev->resolutions_list != NULL)
	{
	  /* This vidcam has a fixed number of supported
	   * resolutions. Find the color sequence for that
	   * resolution. */

	  for (i = 0;
	       dev->hw->color_adjust[i].resolution_x != dev->x_resolution;
	       i++);

	  dev->red_s = dev->hw->color_adjust[i].z1_color_0;
	  dev->green_s = dev->hw->color_adjust[i].z1_color_1;
	  dev->blue_s = dev->hw->color_adjust[i].z1_color_2;
	  dev->y_resolution = dev->hw->color_adjust[i].resolution_y;
	}
      switch (dev->val[OPT_RESOLUTION].w)
	{
	case 176:
	  dev->video_mode = 0x0200;
	  dev->cwidth = dev->x_resolution;
	  dev->cheight = dev->y_resolution;
	  break;
	case 160:
	  dev->video_mode = 0x0300;
	  dev->cwidth = dev->x_resolution;
	  dev->cheight = dev->y_resolution;
	  break;
	case 320:
	  dev->video_mode = 0x0300;
	  dev->cwidth = dev->x_resolution;
	  dev->cheight = dev->y_resolution;
	  break;
	case 352:
	  dev->video_mode = 0x0000;
	  dev->cwidth = dev->x_resolution;
	  dev->cheight = dev->y_resolution;
	  break;
	case 640:
	  dev->video_mode = 0x0100;
	  dev->cwidth = dev->x_resolution;
	  dev->cheight = dev->y_resolution;
	  break;
	}
      dev->params.pixels_per_line = dev->x_resolution;
      dev->params.lines = dev->y_resolution;
      DBG (DBG_info, "sane_get_parameters: x=%d, y=%d\n", dev->x_resolution,
	   dev->y_resolution);
    }

  /* Return the current values. */
  if (params)
    {
      *params = (dev->params);
    }

  DBG (DBG_proc, "sane_get_parameters: exit\n");

  return SANE_STATUS_GOOD;
}

SANE_Status
sane_start (SANE_Handle handle)
{
  Sq930x_Vidcam *dev = handle;
  SANE_Status status;

  DBG (DBG_proc, "sane_start: enter\n");

  if (!(dev->scanning))
    {
      sane_get_parameters (dev, NULL);

      /* Open again the vidcam  */
      if (sanei_usb_open (dev->devicename, &(dev->fd)) != 0)
	{
	  DBG (DBG_error, "ERROR: sane_start: open failed\n");
	  return SANE_STATUS_INVAL;
	}

      /* Initialize the vidcam. */
      status = sq930x_vidcam_init (dev);
      if (status)
	{
	  DBG (DBG_error, "ERROR: failed to init the vidcam\n");
	  sq930x_close (dev);
	  return status;
	}

    }

  dev->image_end = 0;
  dev->image_begin = 0;
  /* real_byte_left is read bulk bytes,
   * bytes_left is frontend buf bytes */
  dev->real_bytes_left = dev->cwidth * dev->cheight + 0x08;
  dev->bytes_left = dev->params.bytes_per_line * dev->params.lines;

  dev->scanning = SANE_TRUE;

  DBG (DBG_proc, "sane_start: exit\n");

  return SANE_STATUS_GOOD;
}

SANE_Status
sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
	   SANE_Int * len)
{
  SANE_Status status;
  Sq930x_Vidcam *dev = handle;
  size_t size;
  int count;
  int x;
  int buf_offset;

  DBG (DBG_proc, "sane_read: enter\n");

  *len = 0;

  if (dev->deliver_eof)
    {
      dev->deliver_eof = 0;
      return SANE_STATUS_EOF;
    }

  if (!(dev->scanning))
    {
      /* OOPS, not scanning, stop a scan. */
      sq930x_reset_vidcam (dev);
      sq930x_close (dev);
      dev->scanning = SANE_FALSE;
      return SANE_STATUS_CANCELLED;
    }

  if (dev->bytes_left <= 0)
    {
      return (SANE_STATUS_EOF);
    }

  if (dev->image_begin == dev->image_end)
    {
      /* Fill image */
      status = sq930x_fill_image (dev);
      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_info, "sane_read: sq930x_fill_image status NOK\n");
	  return (status);
	}
      DBG (DBG_info, "sane_read: sq930x_fill_image end\n");
    }
  /* Something must have been read */
  if (dev->image_begin == dev->image_end)
    {
      DBG (DBG_info, "sane_read: nothing read\n");
      return SANE_STATUS_IO_ERROR;
    }

  if (dev->read_format == 0x00)	/* bitmap mode */
    {
      /* do bayer unshuffle  after complete frame is read BA81->RGB mode */
      status = sq930x_bayer_unshuffle (dev, dev->image, &size);

      if (status != SANE_STATUS_GOOD)
	{
	  DBG (DBG_info, "sane_read: sq930x_bayer_unshuffle status NOK\n");
	  return (status);
	}
    }

  size = dev->bytes_left;
  if (((unsigned int) max_len) < size)
    {
      DBG (DBG_error, "sane_read: max_len < size\n");
      return (SANE_FALSE);
    }
  if ((dev->image_end - dev->image_begin) > size)
    {
      size = dev->image_end - dev->image_begin;
      DBG (DBG_proc, "sane_read: size < dev->image_end - dev->image_begin\n");
    }
  DBG (DBG_info, "sane_read: size =0x%lx bytes, max_len=0x%lx bytes\n",
       (unsigned long) (size_t) size, (unsigned long) (size_t) max_len);

  *len = dev->bytes_left;	/* needed */
  size = dev->bytes_left;
  dev->bytes_left = 0;		/* needed for frontend or ? */

  /* Copy the data to the frontend buffer. */
  memcpy (buf, dev->image, size);


  DBG (DBG_info, "sane_read: leave, bytes_left=%ld\n",
       (long) dev->bytes_left);

  status = SANE_STATUS_GOOD;
  return status;
}

SANE_Status
sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
{

  DBG (DBG_proc, "sane_set_io_mode: enter\n");

  handle = handle;		/* silence gcc */
  non_blocking = non_blocking;	/* silence gcc */


  DBG (DBG_proc, "sane_set_io_mode: exit\n");

  return SANE_STATUS_UNSUPPORTED;
}

SANE_Status
sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
{
  DBG (DBG_proc, "sane_get_select_fd: enter\n");

  handle = handle;		/* silence gcc */
  fd = fd;			/* silence gcc */

  DBG (DBG_proc, "sane_get_select_fd: exit\n");

  return SANE_STATUS_UNSUPPORTED;
}

void
sane_cancel (SANE_Handle handle)
{
  Sq930x_Vidcam *dev = handle;

  DBG (DBG_proc, "sane_cancel: enter\n");

  /* Stop a scan. */
  if (dev->scanning == SANE_TRUE)
    {
      /* Reset the vidcam */
      sq930x_reset_vidcam (dev);
      sq930x_close (dev);
    }
  dev->scanning = SANE_FALSE;
  dev->deliver_eof = 0;

  /* return SANE_STATUS_CANCELLED; */
  DBG (DBG_proc, "sane_cancel: exit\n");
}

void
sane_close (SANE_Handle handle)
{
  Sq930x_Vidcam *dev = handle;
  Sq930x_Vidcam *dev_tmp;

  DBG (DBG_proc, "sane_close: enter\n");

/* Stop a scan. */

  if (dev->scanning == SANE_TRUE)
    {
      sq930x_reset_vidcam (dev);
      sq930x_close (dev);
    }
  dev->scanning = SANE_FALSE;

  /* Unlink dev. */
  if (first_dev == dev)
    {
      first_dev = dev->next;
    }
  else
    {
      dev_tmp = first_dev;
      while (dev_tmp->next && dev_tmp->next != dev)
	{
	  dev_tmp = dev_tmp->next;
	}
      if (dev_tmp->next != NULL)
	{
	  dev_tmp->next = dev_tmp->next->next;
	}
    }

  sq930x_free (dev);
  num_devices--;

  DBG (DBG_proc, "sane_close: exit\n");
}

void
sane_exit (void)
{
  DBG (DBG_proc, "sane_exit: enter\n");

  while (first_dev)
    {
      sane_close (first_dev);
    }

  if (devlist)
    {
      free (devlist);
      devlist = NULL;
    }

  DBG (DBG_proc, "sane_exit: exit\n");
}
