Example #1
0
static SANE_Status
do_cancel (Tamarack_Scanner *s)
{
  s->scanning = SANE_FALSE;
  s->pass = 0;

  do_eof (s);

  if (s->reader_pid != -1)
    {
      int exit_status;

      /* ensure child knows it's time to stop: */
      sanei_thread_kill (s->reader_pid);
      sanei_thread_waitpid (s->reader_pid, &exit_status);
      s->reader_pid = -1;
    }

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

  return SANE_STATUS_CANCELLED;
}
Example #2
0
/* Close device */
void
sane_close (SANE_Handle handle)
{
  struct scanner *s = (struct scanner *) handle;
  unsigned i;
  hopper_down (s);
  if (s->bus == USB)
    {
      sanei_usb_release_interface (s->file, 0);
      sanei_usb_close (s->file);
    }
  else
    sanei_scsi_close (s->file);

  for (i = 1; i < NUM_OPTIONS; i++)
    {
      if (s->opt[i].type == SANE_TYPE_STRING && s->val[i].s)
	free (s->val[i].s);
    }

  for (i = 0; i < sizeof (s->buf) / sizeof (s->buf[0]); i++)
    buf_deinit (&s->buf[i]);

  free (s->buffer);
  free (s);

}
Example #3
0
void
sane_close (SANE_Handle handle)
{
  Ibm_Scanner *s = (Ibm_Scanner *) handle;
  DBG (11, ">> sane_close\n");

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

  DBG (11, ">> sane_close\n");
}
Example #4
0
/* Closes an open scanner. */
static void
leo_close (Leo_Scanner * dev)
{
  DBG (DBG_proc, "leo_close: enter\n");

  if (dev->sfd != -1)
    {
      sanei_scsi_close (dev->sfd);
      dev->sfd = -1;
    }

  DBG (DBG_proc, "leo_close: exit\n");
}
Example #5
0
void
sane_cancel( SANE_Handle handle )
{
	ST400_Device *dev = handle;

	DBG(DCODE, "sane_cancel(%p)\n", handle);

	if( dev->status.scanning ) {
#if 0
		st400_stop_scan(dev->fd);
#endif
		if( st400_light_delay ) 
			st400_light_off(dev->fd);
		st400_release(dev->fd);
		sanei_scsi_close(dev->fd);
		dev->status.scanning = 0;
		dev->fd = -1;
	}
	if( dev->buffer ) {
		free(dev->buffer);
		dev->buffer = NULL;
	}
}
Example #6
0
static SANE_Status
do_cancel (Ibm_Scanner * s)
{
  SANE_Status status;
  DBG (11, ">> do_cancel\n");

  DBG (3, "cancel: sending OBJECT POSITION\n");
  status = object_position (s->fd, OBJECT_POSITION_UNLOAD);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "cancel: OBJECT POSTITION failed\n");
    }

  s->scanning = SANE_FALSE;

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

  DBG (11, "<< do_cancel\n");
  return (SANE_STATUS_CANCELLED);
}
Example #7
0
/* Close device */
void
sane_close (SANE_Handle handle)
{
  struct scanner *s = (struct scanner *) handle;
  int i;
  if (s->bus == USB)
    {
      sanei_usb_release_interface (s->file, 0);
      sanei_usb_close (s->file);
    }
  else
    sanei_scsi_close (s->file);

  for (i = 1; i < NUM_OPTIONS; i++)
    {
      if (s->opt[i].type == SANE_TYPE_STRING && s->val[i].s)
	free (s->val[i].s);
    }
  if (s->data)
    free (s->data);
  free (s->buffer);
  free (s);

}
Example #8
0
static SANE_Status
attach (const char *devnam, Ibm_Device ** devp)
{
  SANE_Status status;
  Ibm_Device *dev;

  int fd;
  struct inquiry_data ibuf;
  struct measurements_units_page mup;
  struct ibm_window_data wbuf;
  size_t buf_size;
  char *str;
  DBG (11, ">> attach\n");

  for (dev = first_dev; dev; dev = dev->next)
    {
      if (strcmp (dev->sane.name, devnam) == 0)
        {
          if (devp)
            *devp = dev;
          return (SANE_STATUS_GOOD);
        }
    }

  DBG (3, "attach: opening %s\n", devnam);
  status = sanei_scsi_open (devnam, &fd, NULL, NULL);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "attach: open failed: %s\n", sane_strstatus (status));
      return (status);
    }

  DBG (3, "attach: sending INQUIRY\n");
  memset (&ibuf, 0, sizeof (ibuf));
  buf_size = sizeof(ibuf);
/* next line by mf */
  ibuf.byte2 = 2;
  status = inquiry (fd, &ibuf, &buf_size);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "attach: inquiry failed: %s\n", sane_strstatus (status));
      sanei_scsi_close (fd);
      return (status);
    }

  if (ibuf.devtype != 6)
    {
      DBG (1, "attach: device \"%s\" is not a scanner\n", devnam);
      sanei_scsi_close (fd);
      return (SANE_STATUS_INVAL);
    }

  if (!(
	(strncmp ((char *)ibuf.vendor, "IBM", 3) ==0
         && strncmp ((char *)ibuf.product, "2456", 4) == 0)
        || (strncmp ((char *)ibuf.vendor, "RICOH", 5) == 0 
	    && strncmp ((char *)ibuf.product, "IS420", 5) == 0) 
        || (strncmp ((char *)ibuf.vendor, "RICOH", 5) == 0 
	    && strncmp ((char *)ibuf.product, "IS410", 5) == 0) 
        || (strncmp ((char *)ibuf.vendor, "RICOH", 5) == 0 
	    && strncmp ((char *)ibuf.product, "IS430", 5) == 0) 
	))
    {
      DBG (1, "attach: device \"%s\" doesn't look like a scanner I know\n",
	   devnam);
      sanei_scsi_close (fd);
      return (SANE_STATUS_INVAL);
    }

  DBG (3, "attach: sending TEST_UNIT_READY\n");
  status = test_unit_ready (fd);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "attach: test unit ready failed (%s)\n",
           sane_strstatus (status));
      sanei_scsi_close (fd);
      return (status);
    }
  /*
   * Causes a problem with RICOH IS420
   * Ignore this function ... seems to work ok
   * Suggested to George Murphy [email protected] by henning
   */
  if (strncmp((char *)ibuf.vendor, "RICOH", 5) != 0
      && strncmp((char *)ibuf.product, "IS420", 5) != 0)
    {
      DBG (3, "attach: sending OBJECT POSITION\n");
      status = object_position (fd, OBJECT_POSITION_UNLOAD);
      if (status != SANE_STATUS_GOOD)
    	{
	  DBG (1, "attach: OBJECT POSTITION failed\n");
	  sanei_scsi_close (fd);
	  return (SANE_STATUS_INVAL);
    	}
    }

  memset (&mup, 0, sizeof (mup));
  mup.page_code = MEASUREMENTS_PAGE;
  mup.parameter_length = 0x06;
  mup.bmu = INCHES;
  mup.mud[0] = (DEFAULT_MUD >> 8) & 0xff;
  mup.mud[1] = (DEFAULT_MUD & 0xff);

#if 0
  DBG (3, "attach: sending MODE SELECT\n");
  status = mode_select (fd, (struct mode_pages *) &mup);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "attach: MODE_SELECT failed\n");
      sanei_scsi_close (fd);
      return (SANE_STATUS_INVAL);
    } 
#endif

#if 0
  DBG (3, "attach: sending MODE SENSE\n");
  memset (&mup, 0, sizeof (mup));
  status = mode_sense (fd, (struct mode_pages *) &mup, PC_CURRENT | MEASUREMENTS_PAGE);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "attach: MODE_SENSE failed\n");
      sanei_scsi_close (fd);
      return (SANE_STATUS_INVAL);
    }
#endif

  DBG (3, "attach: sending GET WINDOW\n");
  memset (&wbuf, 0, sizeof (wbuf));
  status = get_window (fd, &wbuf);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (1, "attach: GET_WINDOW failed %d\n", status);
      sanei_scsi_close (fd);
      DBG (11, "<< attach\n");
      return (SANE_STATUS_INVAL);
    }

  sanei_scsi_close (fd);

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

  dev->sane.name = strdup (devnam);
  dev->sane.vendor = "IBM";
  str = malloc (16 + 1);
  memset (str, 0, sizeof (str));
  strncpy (str, (char *)ibuf.product, sizeof(ibuf.product));
  strncpy (str + sizeof(ibuf.revision), (char *)ibuf.revision, sizeof(ibuf.revision));
  str[sizeof(ibuf.product) + sizeof(ibuf.revision)] = '\0';
  dev->sane.model = str;
  dev->sane.type = "flatbed scanner";

  DBG (5, "dev->sane.name = %s\n", dev->sane.name);
  DBG (5, "dev->sane.vendor = %s\n", dev->sane.vendor);
  DBG (5, "dev->sane.model = %s\n", dev->sane.model);
  DBG (5, "dev->sane.type = %s\n", dev->sane.type);

  dev->info.xres_default = _2btol(wbuf.x_res);
  dev->info.yres_default = _2btol(wbuf.y_res);
  dev->info.image_mode_default = wbuf.image_comp;

  /* if you throw the MRIF bit the brighness control reverses too */
  /* so I reverse the reversal in software for symmetry's sake */
  /* I should make this into an option */

  if (wbuf.image_comp == IBM_GRAYSCALE || wbuf.image_comp == IBM_DITHERED_MONOCHROME)
    {
      dev->info.brightness_default = 256 - wbuf.brightness;
/*
      if (is50)
	dev->info.contrast_default = wbuf.contrast;
      else
*/
      dev->info.contrast_default = 256 - wbuf.contrast;
    }
  else /* wbuf.image_comp == IBM_BINARY_MONOCHROME */
    {
      dev->info.brightness_default = wbuf.brightness;
      dev->info.contrast_default = wbuf.contrast;
    }
  
/* da rivedere
  dev->info.adf_default = wbuf.adf_state;
*/
  dev->info.adf_default = ADF_UNUSED;
  dev->info.adf_default = IBM_PAPER_USER_DEFINED;
  
#if 1
  dev->info.bmu = mup.bmu;
  dev->info.mud = _2btol(mup.mud);
  if (dev->info.mud == 0) {
    /* The Ricoh says it uses points as default Basic Measurement Unit */
    /* but gives a Measurement Unit Divisor of zero */
    /* So, we set it to the default (SCSI-standard) of 1200 */
    /* with BMU in inches, i.e. 1200 points equal 1 inch */
    dev->info.bmu = INCHES;
    dev->info.mud = DEFAULT_MUD;
  }
#else
    dev->info.bmu = INCHES;
    dev->info.mud = DEFAULT_MUD;
#endif

  DBG (5, "xres_default=%d\n", dev->info.xres_default);
  DBG (5, "xres_range.max=%d\n", dev->info.xres_range.max);
  DBG (5, "xres_range.min=%d\n", dev->info.xres_range.min);

  DBG (5, "yres_default=%d\n", dev->info.yres_default);
  DBG (5, "yres_range.max=%d\n", dev->info.yres_range.max);
  DBG (5, "yres_range.min=%d\n", dev->info.yres_range.min);

  DBG (5, "x_range.max=%d\n", dev->info.x_range.max);
  DBG (5, "y_range.max=%d\n", dev->info.y_range.max);

  DBG (5, "image_mode=%d\n", dev->info.image_mode_default);

  DBG (5, "brightness=%d\n", dev->info.brightness_default);
  DBG (5, "contrast=%d\n", dev->info.contrast_default);
  
  DBG (5, "adf_state=%d\n", dev->info.adf_default);

  DBG (5, "bmu=%d\n", dev->info.bmu);
  DBG (5, "mud=%d\n", dev->info.mud);

  ++num_devices;
  dev->next = first_dev;
  first_dev = dev;

  if (devp)
    *devp = dev;

  DBG (11, "<< attach\n");
  return (SANE_STATUS_GOOD);
}
Example #9
0
static SANE_Status
attach (const char *devname, Tamarack_Device **devp)
{
  char result[INQ_LEN];
  int fd;
  Tamarack_Device *dev;
  SANE_Status status;
  size_t size;
  char *mfg, *model;
  char *p;

  for (dev = first_dev; dev; dev = dev->next)
    if (strcmp (dev->sane.name, devname) == 0) {
      if (devp)
	*devp = dev;
      return SANE_STATUS_GOOD;
    }

  DBG(3, "attach: opening %s\n", devname);
  status = sanei_scsi_open (devname, &fd, sense_handler, 0);
  if (status != SANE_STATUS_GOOD) {
    DBG(1, "attach: open failed (%s)\n", sane_strstatus (status));
    return SANE_STATUS_INVAL;
  }

  DBG(3, "attach: sending INQUIRY\n");
  size = sizeof (result);
  status = sanei_scsi_cmd (fd, inquiry, sizeof (inquiry), result, &size);
  if (status != SANE_STATUS_GOOD || size != INQ_LEN) {
    DBG(1, "attach: inquiry failed (%s)\n", sane_strstatus (status));
    sanei_scsi_close (fd);
    return status;
  }

  status = wait_ready (fd);
  sanei_scsi_close (fd);
  if (status != SANE_STATUS_GOOD)
    return status;

  result[33]= '\0';
  p = strchr(result+16,' ');
  if (p) *p = '\0';
  model = strdup (result+16);

  result[16]= '\0';
  p = strchr(result+8,' ');
  if (p) *p = '\0';
  mfg = strdup (result+8);

  DBG(1, "attach: Inquiry gives mfg=%s, model=%s.\n", mfg, model);
  
  if (strcmp (mfg, "TAMARACK") != 0) {
    DBG(1, "attach: device doesn't look like a Tamarack scanner "
	   "(result[0]=%#02x)\n", result[0]);
    return SANE_STATUS_INVAL;
  }
  
  dev = malloc (sizeof (*dev));
  if (!dev)
    return SANE_STATUS_NO_MEM;
  
  memset (dev, 0, sizeof (*dev));

  dev->sane.name   = strdup (devname);
  dev->sane.vendor = "Tamarack";
  dev->sane.model  = model;
  dev->sane.type   = "flatbed scanner";

  dev->x_range.min = 0;
  dev->y_range.min = 0;
  dev->x_range.quant = 0;
  dev->y_range.quant = 0;
  dev->dpi_range.min = SANE_FIX (1);
  dev->dpi_range.quant = SANE_FIX (1);

  dev->x_range.max = SANE_FIX (8.5 * MM_PER_INCH);
  dev->y_range.max = SANE_FIX (11.0 * MM_PER_INCH);
  dev->dpi_range.max = SANE_FIX (600);

  DBG(3, "attach: found Tamarack scanner model %s (%s)\n",
      dev->sane.model, dev->sane.type);

  ++num_devices;
  dev->next = first_dev;
  first_dev = dev;

  if (devp)
    *devp = dev;
  return SANE_STATUS_GOOD;
}
Example #10
0
/* Open device, return the device handle */
SANE_Status
sane_open (SANE_String_Const devname, SANE_Handle * handle)
{
  unsigned i, j, id = 0;
  struct scanner *s;
  SANE_Int h, bus;
  SANE_Status st = SANE_STATUS_GOOD;
  if (!devlist)
    {
      st = sane_get_devices (NULL, 0);
      if (st)
	return st;
    }
  for (i = 0; devlist[i]; i++)
    {
      if (!strcmp (devlist[i]->name, devname))
	break;
    }
  if (!devlist[i])
    return SANE_STATUS_INVAL;
  for (j = 0; j < sizeof (known_devices) / sizeof (known_devices[0]); j++)
    {
      if (!strcmp (devlist[i]->model, known_devices[j].scanner.model))
	{
	  id = known_devices[j].id;
	  break;
	}
    }

  st = sanei_usb_open (devname, &h);

  if (st == SANE_STATUS_ACCESS_DENIED)
    return st;
  if (st)
    {
      st = sanei_scsi_open (devname, &h, kvs40xx_sense_handler, NULL);
      if (st)
	{
	  return st;
	}
      bus = SCSI;
    }
  else
    {
      bus = USB;
      st = sanei_usb_claim_interface (h, 0);
      if (st)
	{
	  sanei_usb_close (h);
	  return st;
	}
    }

  s = malloc (sizeof (struct scanner));
  if (!s)
    return SANE_STATUS_NO_MEM;
  memset (s, 0, sizeof (struct scanner));
  s->buffer = malloc (MAX_READ_DATA_SIZE + BULK_HEADER_SIZE);
  if (!s->buffer)
    return SANE_STATUS_NO_MEM;

  s->file = h;
  s->bus = bus;
  s->id = id;
  strcpy (s->name, devname);
  *handle = s;
  for (i = 0; i < 3; i++)
    {
      st = kvs40xx_test_unit_ready (s);
      if (st)
	{
	  if (s->bus == SCSI)
	    {
	      sanei_scsi_close (s->file);
	      st = sanei_scsi_open (devname, &h, kvs40xx_sense_handler, NULL);
	      if (st)
		return st;
	    }
	  else
	    {
	      sanei_usb_release_interface (s->file, 0);
	      sanei_usb_close (s->file);
	      st = sanei_usb_open (devname, &h);
	      if (st)
		return st;
	      st = sanei_usb_claim_interface (h, 0);
	      if (st)
		{
		  sanei_usb_close (h);
		  return st;
		}
	    }
	  s->file = h;
	}
      else
	break;
    }
  if (i == 3)
    return SANE_STATUS_DEVICE_BUSY;

  if (id == KV_S4085C || id == KV_S4065C)
    {
      char str[16];
      st = inquiry (s, str);
      if (st)
	goto err;
      if (id == KV_S4085C)
	s->id = !strcmp (str, "KV-S4085CL") ? KV_S4085CL : KV_S4085CW;
      else
	s->id = !strcmp (str, "KV-S4065CL") ? KV_S4065CL : KV_S4065CW;
    }
  kvs40xx_init_options (s);
  st = kvs40xx_set_timeout (s, s->val[FEED_TIMEOUT].w);
  if (st)
    goto err;

  return SANE_STATUS_GOOD;
err:
  sane_close (s);
  return st;
}
Example #11
0
static SANE_Status
st400_attach( const char *devname, ST400_Device **devP )
{
	ST400_Device *dev;
	ST400_Model *model;
	SANE_Status status;
	int fd;

	DBG(DCODE, "st400_attach(%s, %p)\n", devname, (void *) devP);
	if( devP )
		*devP = NULL;

	for( dev = st400_devices; dev != NULL; dev = dev->next ) {
		if( strcmp(dev->sane.name, devname) == 0 ) {
			if( devP )
				*devP = dev;
			DBG(DCODE, "st400_attach: found device in list\n");
			return SANE_STATUS_GOOD;
		}
	}

	dev = calloc(1, sizeof(*dev));
	if( !dev )
		return SANE_STATUS_NO_MEM;
	DBG(DCODE, "st400_attach: new device struct at %p\n", (void *) dev);

	status = sanei_scsi_open(devname, &fd, st400_sense_handler, dev);
	if( status == SANE_STATUS_GOOD ) {
		status = st400_inquiry(fd, &model);
		if( status == SANE_STATUS_GOOD )
			status = st400_test_ready(fd);
		sanei_scsi_close(fd);
	}
	if( status != SANE_STATUS_GOOD ) {
		free(dev);
		return status;
	}

	/* initialize device structure */
	dev->sane.name = strdup(devname);
	if( !dev->sane.name ) {
		free(dev);
		return SANE_STATUS_NO_MEM;
	}
	dev->sane.vendor = model->sane_vendor;
	dev->sane.model = model->sane_model;
	dev->sane.type = model->sane_type;
	dev->status.open = 0;
	dev->status.scanning = 0;
	dev->status.eof = 0;
	dev->fd = -1;
	dev->buffer = NULL;
	dev->model = model;

	st400_init_options(dev);

	DBG(DCODE, "st400_attach: everything ok, adding device to list\n");

	dev->next = st400_devices;
	st400_devices = dev;
	++st400_num_devices;
	st400_status.array_valid = 0;

	if( devP )
		*devP = dev;
	return SANE_STATUS_GOOD;
}
Example #12
0
SANE_Status
sane_start( SANE_Handle handle )
{
	ST400_Device *dev = handle;
	SANE_Status status;

	DBG(DCODE, "sane_start(%p)\n", handle);

	if( !dev->status.open )
		return SANE_STATUS_INVAL;
	if( dev->status.scanning )
		return SANE_STATUS_DEVICE_BUSY;

	status = sane_get_parameters(dev, NULL);
	if( status != SANE_STATUS_GOOD )
		return status;

	if( !dev->buffer ) {
		if( st400_maxread > 0 )
			dev->bufsize = min(st400_maxread, (unsigned int) sanei_scsi_max_request_size);
		else
		if( dev->model->maxread > 0 )
			dev->bufsize = min(dev->model->maxread, (unsigned int) sanei_scsi_max_request_size);
		else
			dev->bufsize = sanei_scsi_max_request_size;
		DBG(DVAR, "allocating %lu bytes buffer\n", (u_long)dev->bufsize);
		dev->buffer = malloc(dev->bufsize);
		if( !dev->buffer )
			return SANE_STATUS_NO_MEM;
	}
	dev->bufp = dev->buffer;
	dev->bytes_in_buffer = 0;

	if( dev->fd < 0 ) {
		status = sanei_scsi_open(dev->sane.name, &dev->fd, st400_sense_handler, dev);
		if( status != SANE_STATUS_GOOD )
			goto return_error;
	}

	dev->status.eof = 0;

	status = st400_wait_ready(dev->fd);
	if( status != SANE_STATUS_GOOD )
		goto close_and_return;

	status = st400_reserve(dev->fd);
	if( status != SANE_STATUS_GOOD )
		goto close_and_return;

	if( st400_light_delay > 0 ) {
		status = st400_light_on(dev->fd);
		if( status != SANE_STATUS_GOOD )
			goto release_and_return;
		usleep(st400_light_delay * 100000);	/* 1/10 seconds */
	}

	dev->wy = dev->y;
	dev->lines_to_read = dev->h;
	dev->bytes_in_scanner = 0;

	status = st400_fill_scanner_buffer(dev);
	if( status != SANE_STATUS_GOOD )
		goto lightoff_and_return;

	/* everything ok */
	dev->status.scanning = 1;
	return SANE_STATUS_GOOD;

lightoff_and_return:
	if( st400_light_delay )
		st400_light_off(dev->fd);
release_and_return:
	st400_release(dev->fd);
close_and_return:
	sanei_scsi_close(dev->fd);
return_error:
	dev->fd = -1;
	return status;
}
Example #13
0
static SANE_Status
attach (const char *devname, Abaton_Device ** devp, int may_wait)
{
  char result[INQ_LEN];
  const char *model_name = result + 44;
  int fd, abaton_scanner;
  Abaton_Device *dev;
  SANE_Status status;
  size_t size;

  for (dev = first_dev; dev; dev = dev->next)
    if (strcmp (dev->sane.name, devname) == 0)
      {
	if (devp)
	  *devp = dev;
	return SANE_STATUS_GOOD;
      }

  DBG (USER_MESSAGE, "attach: opening %s\n", devname);
  status = sanei_scsi_open (devname, &fd, sense_handler, 0);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (ERROR_MESSAGE, "attach: open failed (%s)\n",
	   sane_strstatus (status));
      return SANE_STATUS_INVAL;
    }

  if (may_wait)
    wait_ready (fd);

  DBG (USER_MESSAGE, "attach: sending INQUIRY\n");
  size = sizeof (result);
  status = sanei_scsi_cmd (fd, inquiry, sizeof (inquiry), result, &size);
  if (status != SANE_STATUS_GOOD)
    {
      DBG (ERROR_MESSAGE, "attach: inquiry failed (%s)\n",
	   sane_strstatus (status));
      sanei_scsi_close (fd);
      return status;
    }

  status = wait_ready (fd);
  sanei_scsi_close (fd);
  if (status != SANE_STATUS_GOOD)
    return status;

  /* check that we've got an Abaton */
  abaton_scanner = (strncmp (result + 8, "ABATON  ", 8) == 0);
  model_name = result + 16;

  /* make sure it's a scanner ;-) */
  abaton_scanner = abaton_scanner && (result[0] == 0x06);

  if (!abaton_scanner)
    {
      DBG (ERROR_MESSAGE, "attach: device doesn't look like an Abaton scanner "
	   "(result[0]=%#02x)\n", result[0]);
      return SANE_STATUS_INVAL;
    }

  dev = malloc (sizeof (*dev));
  if (!dev)
    return SANE_STATUS_NO_MEM;

  memset (dev, 0, sizeof (*dev));

  dev->sane.name = strdup (devname);
  dev->sane.vendor = "Abaton";
  dev->sane.model = strndup (model_name, 16);
  dev->sane.type = "flatbed scanner";

  if (!strncmp (model_name, "SCAN 300/GS", 11))
    {
      dev->ScannerModel = ABATON_300GS;
    }
  else if (!strncmp (model_name, "SCAN 300/S", 10))
    {
      dev->ScannerModel = ABATON_300S;
    }

  DBG (USER_MESSAGE, "attach: found Abaton scanner model %s (%s)\n",
       dev->sane.model, dev->sane.type);

  ++num_devices;
  dev->next = first_dev;
  first_dev = dev;

  if (devp)
    *devp = dev;

  return SANE_STATUS_GOOD;
}