sane-project-backends/backend/canon_pp.c

2001 wiersze
51 KiB
C

/* sane - Scanner Access Now Easy.
Copyright (C) 2001-2002 Matthew C. Duggan and Simon Krix
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
As a special exception, the authors of SANE give permission for
additional uses of the libraries contained in this release of SANE.
The exception is that, if you link a SANE library with other files
to produce an executable, this does not by itself cause the
resulting executable to be covered by the GNU General Public
License. Your use of that executable is in no way restricted on
account of linking the SANE library code into it.
This exception does not, however, invalidate any other reasons why
the executable file might be covered by the GNU General Public
License.
If you submit changes to SANE to the maintainers to be included in
a subsequent release, you agree by submitting the changes that
those changes may be distributed with this exception intact.
If you write modifications of your own for SANE, it is your choice
whether to permit this exception to apply to your modifications.
If you do not wish that, delete this exception notice.
-----
canon_pp.c: $Revision$
This file is part of the canon_pp backend, supporting Canon FBX30P
and NX40P scanners
*/
#ifdef _AIX
#include <lalloca.h> /* MUST come first for AIX! */
#endif
#define VERSION "$Revision$"
#define BACKEND_NAME canon_pp
#define THREE_BITS 0xE0
#define TWO_BITS 0xC0
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <errno.h>
#include <ieee1284.h>
#include "../include/sane/sane.h"
#include "../include/sane/saneopts.h"
#include "canon_pp-dev.h"
#include "canon_pp-io.h"
#include "canon_pp.h"
/* #include "../include/sane/sanei_pio.h" */
#include "../include/sane/sanei_config.h"
#include "../include/sane/sanei_backend.h"
/* #include "../include/sane/sanei_debug.h" */
/* Prototypes */
static SANE_Status init_device(struct parport *pp);
static void update_ranges(CANONP_Scanner *cs);
/* create a calibration file and give it initial values */
static int init_cal(char *file);
static SANE_Status fix_weights_file(CANONP_Scanner *cs);
static SANE_Status detect_mode(CANONP_Scanner *cs);
/* Global Variables (ack!) */
/* The first device in a linked list of devices */
static CANONP_Scanner *first_dev = NULL;
/* The default scanner to open */
static char *def_scanner = NULL;
/* The number of devices */
static int num_devices = 0;
/* ieee1284 parallel ports */
struct parport_list pl;
/* leftover from the last read */
static SANE_Byte *read_leftover = NULL;
/* leftover from the last read */
static SANE_Bool force_nibble = SANE_FALSE;
/* Constants */
/* Colour Modes */
static const SANE_String_Const cmodes[] = { "Greyscale", "Colour", NULL };
/* bit depths */
static const SANE_String_Const depths[] = { "8", "12", NULL };
/* resolutions */
static const SANE_Int res330[] = {3, 75, 150, 300};
static const SANE_Int res630[] = {4, 75, 150, 300, 600};
/*************************************************************************
*
* sane_init()
*
* Initialises data for the list of scanners, stored in canon-p.conf.
*
* Scanners are not sent any commands until sane_open() is called.
*
*************************************************************************/
SANE_Status
sane_init (SANE_Int *vc, SANE_Auth_Callback cb)
{
SANE_Status status = SANE_STATUS_GOOD;
int i, tmp;
FILE *fp;
char line[80];
char *tmp_wf, *tmp_port;
CANONP_Scanner *s_tmp;
DBG_INIT();
#if defined PACKAGE && defined VERSION
DBG(2, ">> sane_init(%p, %p): " PACKAGE " " VERSION "\n", vc, cb);
#endif
if(vc)
*vc = SANE_VERSION_CODE (V_MAJOR, V_MINOR, 0);
DBG(2,"sane_init: >> ieee1284_find_ports\n");
/* Find lp ports */
tmp = ieee1284_find_ports(&pl, 0);
DBG(2,"sane_init: %d << ieee1284_find_ports\n", tmp);
if (tmp != E1284_OK)
{
DBG(1,"sane_init: Error trying to get port list\n");
return SANE_STATUS_IO_ERROR;
}
if (pl.portc < 1)
{
DBG(1,"sane_init: Error, no parallel ports found.\n");
return SANE_STATUS_IO_ERROR;
}
DBG(10,"sane_init: %i parallel port(s) found.\n", pl.portc);
/* Setup data structures for each port */
for(i=0; i<pl.portc; i++)
{
DBG(10,"sane_init: port %s\n", pl.portv[i]->name);
status = init_device(pl.portv[i]);
/* Now's a good time to quit if we got an error */
if (status != SANE_STATUS_GOOD) return status;
}
/* This should never be true here */
if (num_devices == 0)
status = SANE_STATUS_IO_ERROR;
/*
* Read information from config file: pixel weight location and default
* port.
*/
if((fp = sanei_config_open(CANONP_CONFIG_FILE)))
{
while(sanei_config_read(line, sizeof (line), fp))
{
DBG(100, "sane_init: >%s<\n", line);
if(line[0] == '#') /* ignore line comments */
continue;
if(!strlen(line))
continue; /* ignore empty lines */
if(strncmp(line,"calibrate ", 10) == 0)
{
/* warning: pointer trickyness ahead
* Do not free tmp_port! */
DBG(40, "sane_init: calibrate line, %s\n",
line);
tmp_wf = strdup(line+10);
tmp_port = strstr(tmp_wf, " ");
if ((tmp_port == tmp_wf) || (tmp_port == NULL))
{
/* They have used an old style config
* file which does not specify scanner
* Assume first port */
DBG(1, "sane_init: old config line:"
"\"%s\". Please add "
"a port argument.\n",
line);
/* first_dev should never be null here
* because we found at least one
* parallel port above */
first_dev->weights_file = tmp_wf;
DBG(100, "sane_init: Successfully "
"parsed cal.\n");
continue;
}
/* Now find which scanner wants
* this calibration file */
s_tmp = first_dev;
while (s_tmp != NULL)
{
if (!strcmp(s_tmp->params.port->name,
tmp_port))
{
s_tmp->weights_file = tmp_wf;
break;
DBG(100, "sane_init: "
"Successfully"
" parsed "
"cal.\n");
}
s_tmp = s_tmp->next;
}
if (s_tmp == NULL)
{
/* we made it all the way
* through the list and didn't
* find the port */
free(tmp_wf);
DBG(10, "sane_init: calibrate line is "
"for unknown port!\n");
}
continue;
}
if(strncmp(line,"ieee1284 ", 9) == 0)
{
DBG(100, "sane_init: Successfully parsed "
"default scanner.\n");
/* this will be our default scanner */
def_scanner = strdup(line+9);
continue;
}
if(strncmp(line,"force_nibble", 12) == 0)
{
DBG(100, "sane_init: force_nibble "
"requested.\n");
force_nibble = SANE_TRUE;
continue;
}
DBG(1, "sane_init: Unknown configuration command!");
}
fclose (fp);
}
/* There should now be a LL of ports starting at first_dev */
for (s_tmp = first_dev; s_tmp != NULL; s_tmp = s_tmp->next)
{
/* Assume there's no scanner present until proven otherwise */
s_tmp->scanner_present = SANE_FALSE;
/* Try to detect if there's a scanner there, and if so,
* what sort of scanner it is */
status = detect_mode(s_tmp);
if (status != SANE_STATUS_GOOD)
{
DBG(10,"sane_init: Error detecting port mode on %s!\n",
s_tmp->params.port->name);
s_tmp->scanner_present = SANE_FALSE;
continue;
}
/* detect_mode suceeded, so the port is open. This beholdens
* us to call ieee1284_close in any of the remaining error
* cases in this loop. */
#if 0
tmp = sanei_canon_pp_detect(s_tmp->params.port);
if (tmp && (s_tmp->ieee1284_mode != M1284_NIBBLE))
{
/* A failure, try again in nibble mode... */
DBG(1, "sane_init: Failed on ECP mode, falling "
"back to nibble mode\n");
s_tmp->ieee1284_mode = M1284_NIBBLE;
sanei_canon_pp_set_ieee1284_mode(s_tmp->ieee1284_mode);
tmp = sanei_canon_pp_detect(s_tmp->params.port);
}
/* still no go? */
if (tmp)
{
DBG(1,"sane_init: couldn't find a scanner on port "
"%s\n", s_tmp->params.port->name);
ieee1284_close(s_tmp->params.port);
continue;
}
#endif
/* all signs point to yes, try it out */
if (ieee1284_claim(s_tmp->params.port) != E1284_OK) {
DBG(10, "sane_init: Couldn't claim port %s.\n",
s_tmp->params.port->name);
ieee1284_close(s_tmp->params.port);
continue;
}
DBG(2, "sane_init: >> initialise\n");
tmp = sanei_canon_pp_initialise(&(s_tmp->params));
DBG(2, "sane_init: << %d initialise\n", tmp);
/* put it back to sleep until we're ready to
* open for business again */
sanei_canon_pp_sleep_scanner(s_tmp->params.port);
/* leave the port open but not claimed - this is regardless
* of the return value of initialise */
ieee1284_release(s_tmp->params.port);
if (tmp && (s_tmp->ieee1284_mode != M1284_NIBBLE))
{
/* A failure, try again in nibble mode... */
DBG(1, "sane_init: Failed on ECP mode, falling "
"back to nibble mode\n");
s_tmp->ieee1284_mode = M1284_NIBBLE;
sanei_canon_pp_set_ieee1284_mode(s_tmp->ieee1284_mode);
tmp = sanei_canon_pp_initialise(&(s_tmp->params));
}
if (tmp) {
DBG(10, "sane_init: Couldn't contact scanner on port "
"%s. Maybe it's not a scanner?\n",
s_tmp->params.port->name);
ieee1284_close(s_tmp->params.port);
s_tmp->scanner_present = SANE_FALSE;
continue;
}
/* Finally, we're sure there's a scanner there! Now we
* just have to load the weights file...*/
if (fix_weights_file(s_tmp) != SANE_STATUS_GOOD) {
DBG(1, "sane_init: Eeek! fix_weights_file failed for "
"scanner on port %s!\n",
s_tmp->params.port->name);
ieee1284_close(s_tmp->params.port);
continue;
}
/* Cocked, locked and ready to rock */
s_tmp->hw.model = s_tmp->params.name;
s_tmp->scanner_present = SANE_TRUE;
}
DBG(2, "<< sane_init\n");
return status;
}
/*************************************************************************
*
* sane_get_devices()
*
* Gives a list of devices avaialable. In our case, that's the linked
* list produced by sane_init.
*
*************************************************************************/
SANE_Status
sane_get_devices (const SANE_Device ***dl, SANE_Bool local)
{
static const SANE_Device **devlist;
CANONP_Scanner *dev;
int i;
DBG(2, ">> sane_get_devices (%p, %d)\n", dl, local);
if (dl == NULL)
{
DBG(1, "sane_get_devices: ERROR: devlist pointer is NULL!");
return SANE_STATUS_INVAL;
}
if (devlist != NULL)
{
/* this has been called already */
*dl = devlist;
return SANE_STATUS_GOOD;
}
devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
if (devlist == NULL)
return (SANE_STATUS_NO_MEM);
i = 0;
for (dev = first_dev; dev != NULL; dev = dev->next)
{
if (dev->scanner_present == SANE_TRUE)
{
devlist[i] = &(dev->hw);
i++;
}
}
devlist[i] = NULL;
*dl = devlist;
DBG(2, "<< sane_get_devices\n");
return SANE_STATUS_GOOD;
}
/*************************************************************************
*
* sane_open()
*
* Open the scanner described by name. Ask libieee1284 to claim the port
* and call Simon's init code. Also configure data structures.
*
*************************************************************************/
SANE_Status
sane_open (SANE_String_Const name, SANE_Handle *h)
{
CANONP_Scanner *cs;
SANE_Range *tmp_range;
int tmp;
DBG(2, ">> sane_open (h=%p, name=\"%s\")\n", h, name);
if ((h == NULL) || (name == NULL))
{
DBG(2,"sane_open: Null pointer received!\n");
return SANE_STATUS_INVAL;
}
if (!strlen(name))
{
DBG(10,"sane_open: Empty name given, assuming first/"
"default scanner\n");
if (def_scanner == NULL)
name = first_dev->params.port->name;
else
name = def_scanner;
/* we don't _have_ to fit this name, so _don't_ fail if it's
* not there */
cs = first_dev;
while((cs != NULL) && strcmp(cs->params.port->name, name))
cs = cs->next;
/* if we didn't find the port they want, or there's no scanner
* there, we just want to find _any_ scanner */
if ((cs == NULL) || (cs->scanner_present != SANE_TRUE))
{
cs = first_dev;
while((cs != NULL) &&
(cs->scanner_present == SANE_FALSE))
cs = cs->next;
}
} else {
/* they're dead keen for this name, so _do_ fail if it's
* not there */
cs = first_dev;
while((cs != NULL) && strcmp(cs->params.port->name, name))
cs = cs->next;
}
if (cs == NULL)
{
DBG(2,"sane_open: No scanner found or requested port "
"doesn't exist (%s)\n", name);
return SANE_STATUS_IO_ERROR;
}
if (cs->scanner_present == SANE_FALSE)
{
DBG(1,"sane_open: Request to open port with no scanner "
"(%s)\n", name);
return SANE_STATUS_IO_ERROR;
}
if (cs->opened == SANE_TRUE)
{
DBG(2,"sane_open; Oi!, That scanner's already open.\n");
return SANE_STATUS_DEVICE_BUSY;
}
/* If the scanner has already been opened once, we don't have to do
* this setup again */
if (cs->setup == SANE_TRUE)
{
cs->opened = SANE_TRUE;
*h = (SANE_Handle)cs;
return SANE_STATUS_GOOD;
}
tmp = ieee1284_claim(cs->params.port);
if (tmp != E1284_OK) {
DBG(1, "sane_open: Could not claim port!\n");
return SANE_STATUS_IO_ERROR;
}
/* I put the scanner to sleep before, better wake it back up */
DBG(2, "sane_open: >> initialise\n");
tmp = sanei_canon_pp_initialise(&(cs->params));
DBG(2, "sane_open: << %d initialise\n", tmp);
if (tmp != 0) {
DBG(1, "sane_open: initialise returned %d, something is "
"wrong with the scanner!\n", tmp);
DBG(1, "sane_open: Can't contact scanner. Try power "
"cycling scanner, and unplug any "
"printers\n");
ieee1284_release(cs->params.port);
return SANE_STATUS_IO_ERROR;
}
if (cs->weights_file != NULL)
DBG(2, "sane_open: >> load_weights(%s, %p)\n",
cs->weights_file, &(cs->params));
else
DBG(2, "sane_open: >> load_weights(NULL, %p)\n", &(cs->params));
tmp = sanei_canon_pp_load_weights(cs->weights_file, &(cs->params));
DBG(2, "sane_open: << %d load_weights\n", tmp);
if (tmp != 0) {
DBG(1, "sane_open: WARNING: Error on load_weights: "
"returned %d. This could be due to a corrupt "
"calibration file. Try recalibrating and if "
"problems persist, please report the problem "
"to the canon_pp maintainer\n", tmp);
cs->cal_valid = SANE_FALSE;
} else {
cs->cal_valid = SANE_TRUE;
DBG(10, "sane_open: loadweights successful, uploading gamma"
" profile...\n");
tmp = sanei_canon_pp_adjust_gamma(&(cs->params));
if (tmp != 0)
DBG(1, "sane_open: WARNING: adjust_gamma returned "
"%d!\n", tmp);
DBG(10, "sane_open: after adjust_gamma Status = %i\n",
sanei_canon_pp_check_status(cs->params.port));
}
/* Configure ranges etc */
/* Resolution - determined by magic number */
if (cs->params.scanheadwidth == 2552)
cs->opt[OPT_RESOLUTION].constraint.word_list = res330;
else
cs->opt[OPT_RESOLUTION].constraint.word_list = res630;
/* TL-X */
if(!(tmp_range = (SANE_Range *)malloc(sizeof(SANE_Range))))
return SANE_STATUS_NO_MEM;
(*tmp_range).min = 0;
/* max is set later */
cs->opt[OPT_TL_X].constraint.range = tmp_range;
/* TL-Y */
if(!(tmp_range = (SANE_Range *)malloc(sizeof(SANE_Range))))
return SANE_STATUS_NO_MEM;
(*tmp_range).min = 0;
/* max is set later */
cs->opt[OPT_TL_Y].constraint.range = tmp_range;
/* BR-X */
if(!(tmp_range = (SANE_Range *)malloc(sizeof(SANE_Range))))
return SANE_STATUS_NO_MEM;
(*tmp_range).min = 64;
/* max is set later */
cs->opt[OPT_BR_X].constraint.range = tmp_range;
/* BR-Y */
if(!(tmp_range = (SANE_Range *)malloc(sizeof(SANE_Range))))
return SANE_STATUS_NO_MEM;
(*tmp_range).min = 1;
/* max is set later */
cs->opt[OPT_BR_Y].constraint.range = tmp_range;
/* set the max for all those ranges */
update_ranges(cs);
cs->opened = SANE_TRUE;
cs->setup = SANE_TRUE;
*h = (SANE_Handle)cs;
DBG(2, "<< sane_open\n");
return SANE_STATUS_GOOD;
}
/*************************************************************************
*
* sane_get_option_descriptor()
*
* Return the structure for option number opt.
*
*************************************************************************/
const SANE_Option_Descriptor *
sane_get_option_descriptor (SANE_Handle h, SANE_Int opt)
{
CANONP_Scanner *cs = ((CANONP_Scanner *)h);
/*DBG(2, ">> sane_get_option_descriptor (h=%p, opt=%d)\n", h, opt);*/
if (h == NULL) {
DBG(10,"sane_get_option_descriptor: WARNING: h==NULL!\n");
return NULL;
}
if ((unsigned)opt >= NUM_OPTIONS) {
DBG(10,"sane_get_option_descriptor: Note: opt >= "
"NUM_OPTIONS!\n");
return NULL;
}
if (cs->opened == SANE_FALSE)
{
DBG(1,"sane_get_option_descriptor: That scanner (%p) ain't "
"open yet\n", cs);
return NULL;
}
/*DBG(2, "<< sane_get_option_descriptor\n");*/
return (cs->opt + opt);
}
/*************************************************************************
*
* sane_control_option()
*
* Set a value for one of the options provided.
*
*************************************************************************/
SANE_Status
sane_control_option (SANE_Handle h, SANE_Int opt, SANE_Action act,
void *val, SANE_Word *info)
{
CANONP_Scanner *cs = ((CANONP_Scanner *)h);
int i = 0, tmp, maxresi;
DBG(2, ">> sane_control_option (h=%p, opt=%d, act=%d)\n",
h,opt,act);
/* Do some sanity checks on the parameters
* note that val can be null for buttons */
if ((h == NULL) || ((val == NULL) && (opt != OPT_CAL)))
/* || (info == NULL)) - Don't check this any more..
* frontends seem to like passing a null */
{
DBG(1,"sane_control_option: Frontend passed me a null! "
"(h=%p,val=%p,info=%p)\n",h,val,info);
return SANE_STATUS_INVAL;
}
if (((unsigned)opt) >= NUM_OPTIONS)
{
DBG(1,"sane_control_option: I don't do option %d.\n", opt);
return SANE_STATUS_INVAL;
}
if (cs->opened == SANE_FALSE)
{
DBG(1,"sane_control_option: That scanner (%p) ain't "
"open yet\n", cs);
return SANE_STATUS_INVAL;
}
if (cs->scanning == SANE_TRUE)
{
DBG(1,"sane_control_option: That scanner (%p) is scanning!\n",
cs);
return SANE_STATUS_DEVICE_BUSY;
}
switch(act)
{
case SANE_ACTION_GET_VALUE:
switch (opt)
{
case OPT_COLOUR_MODE:
strcpy((char *)val,
cmodes[cs->vals[opt]]);
break;
case OPT_DEPTH:
strcpy((char *)val,
depths[cs->vals[opt]]);
break;
case OPT_RESOLUTION:
*((int *)val) = res630[cs->vals[opt]];
break;
default:
*((int *)val) = cs->vals[opt];
break;
}
break;
case SANE_ACTION_SET_VALUE:
/* val has been checked for NULL if opt != OPT_CAL */
if (opt != OPT_CAL) i = *((int *)val);
if (info != NULL) *info = 0;
switch (opt) {
case OPT_NUM_OPTIONS:
/* you can't set that! */
return SANE_STATUS_INVAL;
case OPT_RESOLUTION:
i = cs->vals[opt];
cs->vals[opt] = 1;
maxresi = cs->opt[OPT_RESOLUTION].
constraint.word_list[0];
while ((cs->vals[opt] <= maxresi) &&
(res630[cs->vals[opt]]
< *((int *)val)))
{
cs->vals[opt] += 1;
}
if (cs->vals[opt] != i)
{
update_ranges(cs);
/* shouldn't have to reload
* params too, but xsane
* seems a bit buggy in that
* respect. it's ok for us
* not to change them */
if (info != NULL) *info |=
SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
}
if (res630[cs->vals[opt]] !=
*((int *)val))
{
if (info != NULL) *info |=
SANE_INFO_INEXACT;
}
break;
case OPT_COLOUR_MODE:
cs->vals[opt] = 0;
while ((cmodes[cs->vals[opt]] != NULL)
&& strcmp(cmodes[cs->vals[opt]],
(char *)val))
{
cs->vals[opt] += 1;
}
if (info != NULL) *info |=
SANE_INFO_RELOAD_PARAMS;
break;
case OPT_DEPTH:
cs->vals[opt] = 0;
while ((depths[cs->vals[opt]] != NULL)
&& strcmp(depths[cs->vals[opt]],
(char *)val))
{
cs->vals[opt] += 1;
}
if (info != NULL) *info |=
SANE_INFO_RELOAD_PARAMS;
break;
case OPT_TL_X:
case OPT_BR_X:
if ((i<cs->opt[opt].constraint.range->min) || (i>cs->opt[opt].constraint.range->max))
return SANE_STATUS_INVAL;
/* Rnd up to the next multiple of 4 */
if (i % 4) {
DBG(100, "Inexact: X requested"
": %d,",i);
if (opt == OPT_TL_X)
i -= (i % 4);
else
i += 4 - (i % 4);
DBG(100, " X provided: %d\n",i);
if (info != NULL) *info |=
SANE_INFO_INEXACT;
}
cs->vals[opt] = i;
break;
case OPT_TL_Y:
case OPT_BR_Y:
if ((i<cs->opt[opt].constraint.range->min) || (i>cs->opt[opt].constraint.range->max))
return SANE_STATUS_INVAL;
cs->vals[opt] = i;
break;
case OPT_CAL:
/* Call the calibration code */
if ((cs->weights_file==NULL) ||
cs->cal_readonly
)
DBG(2, ">> calibrate(%p, "
"NULL)\n",
&(cs->params));
else
DBG(2, ">> calibrate(%p,"
"%s)\n",
&(cs->params),
cs->weights_file);
if (cs->cal_readonly) tmp =
sanei_canon_pp_calibrate(
&(cs->params),
NULL);
else tmp = sanei_canon_pp_calibrate(
&(cs->params),
cs->weights_file);
DBG(2, "<< %d calibrate\n",
tmp);
if (tmp != 0) {
DBG(1, "sane_control_option: "
"WARNING: "
"calibrate "
"returned %d!",
tmp);
cs->cal_valid =
SANE_FALSE;
return SANE_STATUS_IO_ERROR;
} else {
cs->cal_valid =
SANE_TRUE;
}
break;
/*case OPT_PREVIEW:
if (i) cs->vals[opt] = 1;
else cs->vals[opt] = 0;
break;*/
default:
/* Should never happen */
return SANE_STATUS_INVAL;
}
break;
case SANE_ACTION_SET_AUTO:
DBG(2, "sane_control_option: attempt at "
"automatic control! (unsupported)\n");
/* Auto? are they mad? I'm not that smart! */
/* fall through. */
default:
return SANE_STATUS_INVAL;
}
DBG(2, "<< sane_control_option\n");
return SANE_STATUS_GOOD;
}
/*************************************************************************
*
* sane_get_parameters()
*
* Get information about the next packet. If a scan hasn't started, results
* only have to be best guesses.
*
*************************************************************************/
SANE_Status
sane_get_parameters (SANE_Handle h, SANE_Parameters *params)
{
CANONP_Scanner *cs = ((CANONP_Scanner *)h);
SANE_Int total_lines = 0;
DBG(2, ">> sane_get_parameters (h=%p, params=%p)\n", h, params);
if (h == NULL) return SANE_STATUS_INVAL;
if (cs->opened == SANE_FALSE)
{
DBG(1,"sane_get_parameters: That scanner (%p) ain't "
"open yet\n", cs);
return SANE_STATUS_INVAL;
}
/*
* These don't change whether we're scanning or not
* NOTE: Assumes options don't change after scanning commences
*/
total_lines = cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y];
params->depth = cs->vals[OPT_DEPTH] ? 16 : 8;
switch (cs->vals[OPT_COLOUR_MODE])
{
case 0:
params->format = SANE_FRAME_GRAY;
break;
case 1:
params->format = SANE_FRAME_RGB;
break;
default:
/* shouldn't happen */
break;
}
params->pixels_per_line = cs->vals[OPT_BR_X] - cs->vals[OPT_TL_X];
if (!(params->pixels_per_line)) {
params->last_frame = SANE_TRUE;
params->lines = 0;
}
/* Always assume next packet will be the last
* - frontends seem to like it that way */
params->last_frame = SANE_TRUE;
params->lines = total_lines - cs->lines_scanned;
switch (cs->vals[OPT_COLOUR_MODE])
{
case 0: /* Grey */
params->bytes_per_line =
params->pixels_per_line * (params->depth/8);
break;
case 1: /* Colour */
params->bytes_per_line =
params->pixels_per_line * (params->depth/8) * 3;
break;
default:
/* shouldn't happen */
break;
}
/* FIXME: Do we need to account for the scanner's max buffer here? */
DBG(2, "<< sane_get_parameters\n");
return SANE_STATUS_GOOD;
}
/*************************************************************************
*
* sane_start()
*
* Starts scanning an image.
*
*************************************************************************/
SANE_Status
sane_start (SANE_Handle h)
{
int i,tmp;
CANONP_Scanner *cs = ((CANONP_Scanner *)h);
DBG(2, ">> sane_start (h=%p)\n", h);
if (h == NULL) return SANE_STATUS_INVAL;
if (cs->scanning) return SANE_STATUS_DEVICE_BUSY;
if (cs->opened == SANE_FALSE)
{
DBG(1,"sane_start: That scanner (%p) ain't "
"open yet\n", cs);
return SANE_STATUS_INVAL;
}
/* Copy the options stored in the vals into the scaninfo */
cs->scan.width = cs->vals[OPT_BR_X] - cs->vals[OPT_TL_X];
cs->scan.height = cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y];
cs->scan.xoffset = cs->vals[OPT_TL_X];
cs->scan.yoffset = cs->vals[OPT_TL_Y];
if (((cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y]) <= 0) ||
((cs->vals[OPT_BR_X] - cs->vals[OPT_TL_X]) <= 0))
{
DBG(1,"sane_start: height = %d, Width = %d. "
"Can't scan void range!",
cs->scan.height, cs->scan.width);
return SANE_STATUS_INVAL;
}
/* We use 630 res list here because the 330 res list is just a shorter
* version, so this will always work. */
tmp = res630[cs->vals[OPT_RESOLUTION]];
DBG(10, "sane_start: val=%d, tmp=%d\n",
cs->vals[OPT_RESOLUTION], tmp);
/* We pass a value to init_scan which is the power of 2 that 75
* is multiplied for the resolution. ie:
* 75 -> 0
* 150 -> 1
* 300 -> 2
* 600 -> 4
*
* This rather strange parameter is a result of the way the scanner
* takes its resolution argument
*/
i = 0;
while (tmp > 75)
{
i++;
tmp = tmp >> 1;
}
/* FIXME? xres == yres for now. */
cs->scan.xresolution = i;
cs->scan.yresolution = i;
cs->scan.mode = cs->vals[OPT_COLOUR_MODE];
DBG(10, ">> init_scan(%p, %p)\n", &(cs->params), &(cs->scan));
tmp = sanei_canon_pp_init_scan(&(cs->params), &(cs->scan));
DBG(10, "<< %d init_scan\n", tmp);
if (tmp != 0) {
DBG(1,"sane_start: WARNING: init_scan returned %d!", tmp);
return SANE_STATUS_IO_ERROR;
}
cs->scanning = SANE_TRUE;
cs->cancelled = SANE_FALSE;
cs->sent_eof = SANE_FALSE;
/* init_scan doesn't return a value yet... but Simon might get keen
* one day
if (!(init_scan(&(cs->params), &(cs->scan))))
{
cs->scanning = SANE_TRUE;
return SANE_STATUS_GOOD;
}
else
{
cs->scanning = SANE_FALSE;
return SANE_STATUS_IO_ERROR;
}
*/
DBG(2, "<< sane_start\n");
return SANE_STATUS_GOOD;
}
/*************************************************************************
*
* sane_read()
*
* Reads some information from the buffer.
*
*************************************************************************/
SANE_Status
sane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp)
{
CANONP_Scanner *cs = ((CANONP_Scanner *)h);
image_segment *is;
unsigned int lines, bytes, bpl;
unsigned int i;
short *shortptr;
SANE_Byte *charptr;
int max_buf, tmp;
static SANE_Byte *lbuf;
static unsigned int bytesleft;
DBG(2, ">> sane_read (h=%p, buf=%p, maxlen=%d)\n", h, buf, maxlen);
/* default to returning 0 - for errors */
*lenp = 0;
if ((h == NULL) || (buf == NULL) || (lenp == NULL))
{
DBG(1, "sane_read: This frontend's passing me dodgy gear! "
"(h=%p, buf=%p, lenp=%p)\n",
h, buf, lenp);
return SANE_STATUS_INVAL;
}
/* Now we have to see if we have some leftover from last time */
if (read_leftover != NULL) {
/* feed some more data in until we've run out - don't care
* whether or not we _think_ the scanner is scanning now,
* because we may still have data left over to send */
/* Now feed it some data from lbuf */
if (bytesleft <= (unsigned int)maxlen)
{
/* enough buffer to send the lot */
memcpy(buf, lbuf, bytesleft);
free(lbuf);
*lenp = bytesleft;
lbuf = NULL;
read_leftover = NULL;
bytesleft = 0;
return SANE_STATUS_GOOD;
} else {
/* only enough to send maxlen */
memcpy(buf, lbuf, maxlen);
read_leftover = lbuf + maxlen;
bytesleft -= maxlen;
*lenp = maxlen;
return SANE_STATUS_GOOD;
}
} else {
/* fix potential memory leak if cancelling at the very end
* of a scan */
if (lbuf != NULL) free(lbuf);
lbuf = NULL;
}
/* Has the last scan ended? */
if (((unsigned)cs->scan.height == (unsigned)cs->lines_scanned)
|| !(cs->scanning))
{
if (cs->cancelled)
return SANE_STATUS_CANCELLED;
if (cs->sent_eof)
{
/* It's over mate, get over it */
DBG(10, "sane_read: Already sent EOF!\n");
return SANE_STATUS_INVAL;
} else {
cs->sent_eof = SANE_TRUE;
return SANE_STATUS_EOF;
}
}
/* At this point we have to read more data from the scanner */
/* Decide how many lines we can fit into this buffer */
if (cs->vals[OPT_DEPTH] == 0)
bpl = cs->scan.width * (cs->vals[OPT_COLOUR_MODE] ? 3 : 1);
else
bpl = cs->scan.width * (cs->vals[OPT_COLOUR_MODE] ? 6 : 2);
/* We will have as many lines as possible, or the size of the scan.
* Each pixel is 5/4 bytes per colour, so we multiply the buffer
* size by 4/5 to get the number of lines. */
if ((int)maxlen > (BUF_MAX * 4 / 5))
max_buf = (BUF_MAX * 4 / 5);
else
max_buf = (int)maxlen;
lines = max_buf / (int)bpl;
if (lines > cs->scan.height) lines = cs->scan.height;
if ((cs->scan.height - cs->lines_scanned) < lines)
lines = cs->scan.height - cs->lines_scanned;
if (!lines)
{
/* can't fit a whole line into the buffer */
DBG(10, "sane_read: Tighter than a duck's butt (can't fit a "
"whole scanline in the buffer)\n");
/* return SANE_STATUS_INVAL; */
/* Try and deal with this gracefully */
lines = 1;
}
bytes = lines * bpl;
/* Allocate a local buffer to hold the data while we play */
if ((lbuf = malloc(bytes)) == NULL)
{
DBG(10, "sane_read: Not enough memory to hold a "
"local buffer. You're doomed\n");
return SANE_STATUS_NO_MEM;
}
/* This call required a lot of debugging information.. */
DBG(10, "sane_read: Here's what we're sending read_segment:\n");
DBG(10, "scanner setup: shw=%d xres=%d yres=%d %d %d id=%s\n",
cs->params.scanheadwidth,
cs->params.natural_xresolution,
cs->params.natural_yresolution,
cs->params.max_xresolution,
cs->params.max_yresolution,
(cs->params.id_string)+8);
DBG(10, "scan_params->: width=%d, height=%d, xoffset=%d, "
"yoffset=%d\n\txresolution=%d, yresolution=%d, "
"mode=%d\n\n",
cs->scan.width, cs->scan.height,
cs->scan.xoffset, cs->scan.yoffset,
cs->scan.xresolution, cs->scan.yresolution,
cs->scan.mode
);
DBG(10, "lines=%d\n",lines);
DBG(2, ">> read_segment(%p, %p, %p, %d)\n",
&is, &(cs->params), &(cs->scan), lines);
tmp = sanei_canon_pp_read_segment(&is, &(cs->params),
&(cs->scan), lines, cs->cal_valid);
DBG(2, "<< %d read_segment\n", tmp);
if (tmp != 0) {
DBG(1, "sane_read: WARNING: read_segment returned %d!\n", tmp);
return SANE_STATUS_IO_ERROR;
}
DBG(10, "sane_read: bpl=%d, lines=%d, bytes=%d\n", bpl, lines, bytes);
cs->lines_scanned += lines;
/* translate data out of buffer */
if (cs->vals[OPT_COLOUR_MODE] == 0)
{
/* fudge because simon's code is slack and returns greyscale as
* RGB data, just with the same stuff in R,G,B. */
DBG(10, "sane_read: Initialising FUDGE engine 1.0\n");
if (cs->vals[OPT_DEPTH] == 0)
{
/* 8bpp */
for(i = 0; i < bytes * 3; i += 3)
{
*((char *)lbuf + i/3) =
*((char *)(is->image_data) + (i*2));
}
}
else
{
/* 16bpp */
for(i = 0; i < (bytes/2) * 3; i += 3)
{
/* Convert bigendian data to the local system */
*((short *)lbuf + i/3) = MAKE_SHORT(
*((char *)(is->image_data)
+ (i*2)),
*((char *)(is->image_data)
+ (i*2)+1)
);
}
}
}
else
{
if (cs->vals[OPT_DEPTH] == 0)
{
/* 8bpp */
for(i = 0; i < bytes; i++)
{
charptr = lbuf + i;
if (i % 3 == 0) charptr += 2;
if (i % 3 == 2) charptr -= 2;
*(charptr) =
*((char *)(is->image_data) + (i*2));
}
}
else
{
/* 16bpp */
for(i = 0; i < (bytes/2); i++)
{
shortptr = ((short *)lbuf + i);
if (i % 3 == 0) shortptr += 2;
if (i % 3 == 2) shortptr -= 2;
*shortptr = MAKE_SHORT(
*((char *)(is->image_data) +
(i*2)),
*((char *)(is->image_data) +
(i*2)+1));
}
}
}
/* Now feed it some data from lbuf */
if (bytes <= (unsigned int)maxlen)
{
/* enough buffer to send the lot */
memcpy(buf, lbuf, bytes);
*lenp = bytes;
free(lbuf);
lbuf = NULL;
read_leftover = NULL;
bytesleft = 0;
} else {
/* only enough to send maxlen */
memcpy(buf, lbuf, maxlen);
*lenp = maxlen;
read_leftover = lbuf + maxlen;
bytesleft = bytes - maxlen;
}
if ((unsigned)cs->lines_scanned >= cs->scan.height)
{
/* The scan is over! Don't need to call anything in the
* hardware, it will sort itself out */
DBG(10, "sane_read: Scan is finished.\n");
cs->scanning = SANE_FALSE;
cs->lines_scanned = 0;
}
DBG(2, "<< sane_read\n");
return SANE_STATUS_GOOD;
}
/*************************************************************************
*
* sane_cancel()
*
* Cancels a scan in progress
*
*************************************************************************/
void
sane_cancel (SANE_Handle h)
{
int tmp;
/* Note: assume handle is valid apart from NULLs */
CANONP_Scanner *cs = ((CANONP_Scanner *)h);
DBG(2, ">> sane_cancel (h=%p)\n", h);
if (h == NULL) return;
if (cs->scanning == SANE_FALSE)
{
/* ensure we don't try to send old data */
read_leftover = NULL;
return;
}
cs->scanning = SANE_FALSE;
/* cs->sent_eof = SANE_TRUE; */
cs->cancelled = SANE_TRUE;
cs->lines_scanned = 0;
DBG(2, "sane_cancel: >> abort_scan\n");
tmp = sanei_canon_pp_abort_scan(&(cs->params), &(cs->scan));
DBG(2, "sane_cancel: << abort_scan\n");
if (tmp != 0) {
DBG(1, "sane_cancel: WARNING: abort_scan returned %d!", tmp);
}
DBG(2, "<< sane_cancel\n");
}
/*************************************************************************
*
* sane_close()
*
* Closes a scanner handle. Scanner is assumed to be free after this.
*
*************************************************************************/
void
sane_close (SANE_Handle h)
{
/* Note: assume handle is valid apart from NULLs */
CANONP_Scanner *cs = ((CANONP_Scanner *)h);
DBG(2, ">> sane_close (h=%p)\n", h);
if (h == NULL) return;
if (cs->opened == SANE_FALSE)
{
DBG(1,"sane_close: That scanner (%p) ain't "
"open yet\n", cs);
return;
}
/* Put scanner back in transparent mode */
sanei_canon_pp_close_scanner(&(cs->params));
cs->opened = SANE_FALSE;
/* if it was scanning, it's not any more */
cs->scanning = SANE_FALSE;
cs->sent_eof = SANE_TRUE;
ieee1284_release(cs->params.port);
DBG(2, "<< sane_close\n");
}
/*************************************************************************
*
* sane_exit()
*
* Shut it down!
*
*************************************************************************/
void
sane_exit (void)
{
CANONP_Scanner *dev, *next;
DBG(2, ">> sane_exit\n");
for (dev = first_dev; dev != NULL; dev = next)
{
next = dev->next;
/* These were only created if the scanner has been init'd */
/* Should normally nullify pointers after freeing, but in
* this case we're about to free the whole structure so
* theres not a lot of point. */
/* Constraints (mostly) allocated when the scanner is opened */
if(dev->opt[OPT_TL_X].constraint.range)
free((void *)(dev->opt[OPT_TL_X].constraint.range));
if(dev->opt[OPT_TL_Y].constraint.range)
free((void *)(dev->opt[OPT_TL_Y].constraint.range));
if(dev->opt[OPT_BR_X].constraint.range)
free((void *)(dev->opt[OPT_BR_X].constraint.range));
if(dev->opt[OPT_BR_Y].constraint.range)
free((void *)(dev->opt[OPT_BR_Y].constraint.range));
/* Weights file now on a per-scanner basis */
if (dev->weights_file != NULL)
free(dev->weights_file);
if (dev->scanner_present)
{
if (dev->opened == SANE_TRUE)
{
/* naughty boys, should have closed first */
ieee1284_release(dev->params.port);
}
ieee1284_close(dev->params.port);
}
free (dev);
}
first_dev = NULL;
/* FIXEDME: this creates a segfault in DLL code. */
/* freeing something it shouldn't perhaps? */
/* Turns out to be a bug in libieee1284 0.1.4 and only occurs on 2.2
* kernels - have sent mail to Tim Waugh, will leave commented out
* until I receive a reply */
/* ieee1284_free_ports(&pl); */
DBG(2, "<< sane_exit\n");
}
/*************************************************************************
*
* init_device()
*
* (Not part of the SANE API)
*
* Initialises a CANONP_Scanner data structure for a new device.
* NOTE: The device is not ready to scan until initialise() has been
* called in scan library!
*
*************************************************************************/
static SANE_Status init_device(struct parport *pp)
{
int i;
static const char *hw_vendor = "CANON";
static const char *hw_type = "flatbed scanner";
static const char *opt_names[] = {
SANE_NAME_NUM_OPTIONS,
SANE_NAME_SCAN_RESOLUTION,
SANE_NAME_SCAN_MODE,
SANE_NAME_BIT_DEPTH,
SANE_NAME_SCAN_TL_X,
SANE_NAME_SCAN_TL_Y,
SANE_NAME_SCAN_BR_X,
SANE_NAME_SCAN_BR_Y,
SANE_NAME_QUALITY_CAL
#if 0
SANE_NAME_GAMMA_R,
SANE_NAME_GAMMA_G,
SANE_NAME_GAMMA_B
#endif
};
static const char *opt_titles[] = {
SANE_TITLE_NUM_OPTIONS,
SANE_TITLE_SCAN_RESOLUTION,
SANE_TITLE_SCAN_MODE,
SANE_TITLE_BIT_DEPTH,
SANE_TITLE_SCAN_TL_X,
SANE_TITLE_SCAN_TL_Y,
SANE_TITLE_SCAN_BR_X,
SANE_TITLE_SCAN_BR_Y,
SANE_TITLE_QUALITY_CAL
#if 0
SANE_TITLE_GAMMA_R,
SANE_TITLE_GAMMA_G,
SANE_TITLE_GAMMA_B
#endif
};
static const char *opt_descs[] = {
SANE_DESC_NUM_OPTIONS,
SANE_DESC_SCAN_RESOLUTION,
SANE_DESC_SCAN_MODE,
SANE_DESC_BIT_DEPTH,
SANE_DESC_SCAN_TL_X,
SANE_DESC_SCAN_TL_Y,
SANE_DESC_SCAN_BR_X,
SANE_DESC_SCAN_BR_Y,
SANE_DESC_QUALITY_CAL
#if 0
SANE_DESC_GAMMA_R,
SANE_DESC_GAMMA_G,
SANE_DESC_GAMMA_B
#endif
};
CANONP_Scanner *cs = NULL;
DBG(2, ">> init_device\n");
cs = malloc (sizeof (CANONP_Scanner));
if (cs == NULL)
{
return SANE_STATUS_NO_MEM;
}
memset (cs, 0, sizeof (CANONP_Scanner));
#if 0
if ((cs->params.port = malloc(sizeof(*pp))) == NULL)
return SANE_STATUS_NO_MEM;
memcpy(cs->params.port, pp, sizeof(*pp));
#endif
cs->params.port = pp;
/* ensure these are null to start off with, otherwise they might be
* erroneously free'd. Note that we set everything to 0 above
* but that's not *always* the same thing */
cs->params.blackweight = NULL;
cs->params.redweight = NULL;
cs->params.greenweight = NULL;
cs->params.blueweight = NULL;
/* Set some sensible defaults */
cs->hw.name = cs->params.port->name;
cs->hw.vendor = hw_vendor;
cs->hw.type = hw_type;
cs->opened = SANE_FALSE;
cs->scanning = SANE_FALSE;
cs->cancelled = SANE_FALSE;
cs->sent_eof = SANE_TRUE;
DBG(10, "init_device: [configuring options]\n");
/* take a punt at each option, then we change it later */
for (i = 0; i < NUM_OPTIONS; i++)
{
cs->opt[i].name = opt_names[i];
cs->opt[i].title = opt_titles[i];
cs->opt[i].desc = opt_descs[i];
cs->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
cs->opt[i].type = SANE_TYPE_INT;
cs->opt[i].size = sizeof(SANE_Int);
}
DBG(100, "init_device: configuring opt: num_options\n");
/* The number of options option */
cs->opt[OPT_NUM_OPTIONS].unit = SANE_UNIT_NONE;
cs->opt[OPT_NUM_OPTIONS].cap = SANE_CAP_SOFT_DETECT;
cs->vals[OPT_NUM_OPTIONS] = NUM_OPTIONS;
DBG(100, "init_device: configuring opt: resolution\n");
/* The resolution of scanning (X res == Y res for now)*/
cs->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
cs->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
/* should never point at first element (wordlist size) */
cs->vals[OPT_RESOLUTION] = 1;
DBG(100, "init_device: configuring opt: colour mode\n");
/* The colour mode (0=grey 1=rgb) */
cs->opt[OPT_COLOUR_MODE].type = SANE_TYPE_STRING;
cs->opt[OPT_COLOUR_MODE].size = 20;
cs->opt[OPT_COLOUR_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
/* Set this one here because it doesn't change by scanner (yet) */
cs->opt[OPT_COLOUR_MODE].constraint.string_list = cmodes;
DBG(100, "init_device: configuring opt: bit depth\n");
/* The bit depth */
cs->opt[OPT_DEPTH].type = SANE_TYPE_STRING;
cs->opt[OPT_DEPTH].size = 20;
cs->opt[OPT_DEPTH].cap |= SANE_CAP_EMULATED;
cs->opt[OPT_DEPTH].constraint_type = SANE_CONSTRAINT_STRING_LIST;
cs->opt[OPT_DEPTH].constraint.string_list = depths;
DBG(100, "init_device: configuring opt: tl-x\n");
/* The top-left-x */
cs->opt[OPT_TL_X].unit = SANE_UNIT_PIXEL;
cs->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
DBG(100, "init_device: configuring opt: tl-y\n");
/* The top-left-y */
cs->opt[OPT_TL_Y].unit = SANE_UNIT_PIXEL;
cs->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
DBG(100, "init_device: configuring opt: br-x\n");
/* The bottom-right-x */
cs->opt[OPT_BR_X].unit = SANE_UNIT_PIXEL;
cs->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
/* default scan width */
cs->vals[OPT_BR_X] = 100;
DBG(100, "init_device: configuring opt: br-y\n");
/* The bottom-right-y */
cs->opt[OPT_BR_Y].unit = SANE_UNIT_PIXEL;
cs->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
cs->vals[OPT_BR_Y] = 100;
DBG(100, "init_device: configuring opt: calibrate\n");
/* The calibration button */
cs->opt[OPT_CAL].type = SANE_TYPE_BUTTON;
cs->opt[OPT_CAL].constraint_type = SANE_CONSTRAINT_NONE;
if (cs->cal_readonly)
cs->opt[OPT_CAL].cap |= SANE_CAP_INACTIVE;
#if 0
/* the gamma values (once we do them) */
cs->opt[OPT_GAMMA_R].caps |= SANE_CAP_ADVANCED;
cs->opt[OPT_GAMMA_G].caps |= SANE_CAP_ADVANCED;
cs->opt[OPT_GAMMA_B].caps |= SANE_CAP_ADVANCED;
#endif
/*
* NOTE: Ranges and lists are actually set when scanner is opened,
* becase that's when we find out what sort of scanner it is
*/
DBG(100, "init_device: done opts\n");
/* add it to the head of the tree */
cs->next = first_dev;
first_dev = cs;
num_devices++;
DBG(2, "<< init_device\n");
return SANE_STATUS_GOOD;
}
/*************************************************************************
*
* These two are optional ones... maybe if I get really keen?
*
*************************************************************************/
SANE_Status
sane_set_io_mode (SANE_Handle h, SANE_Bool non_blocking)
{
DBG(2, ">> sane_set_io_mode (%p, %d) (not really supported)\n",
h, non_blocking);
if (non_blocking == SANE_FALSE)
return SANE_STATUS_GOOD;
DBG(2, "<< sane_set_io_mode\n");
return SANE_STATUS_UNSUPPORTED;
}
SANE_Status
sane_get_select_fd (SANE_Handle h, SANE_Int *fdp)
{
DBG(2, ">> sane_get_select_fd (%p, %p) (not supported)\n", h, fdp);
DBG(2, "<< sane_get_select_fd\n");
return SANE_STATUS_UNSUPPORTED;
}
/*************************************************************************
*
* update_ranges(): when the res is changed, the max scan size in pixels
* has to be changed.
*
*************************************************************************/
static void update_ranges(CANONP_Scanner *cs)
{
int new_width, new_height, max_res;
/* FIXME: Magic numbers ahead! */
max_res = cs->params.scanheadwidth == 2552 ? 300 : 600;
new_width = cs->params.scanheadwidth /
(max_res / res630[cs->vals[OPT_RESOLUTION]]);
new_height = (cs->params.scanheadwidth == 2552 ? 3508 : 7016) /
(max_res / res630[cs->vals[OPT_RESOLUTION]]);
/* Max width has to be divisible by 4 */
new_width -= (new_width%4);
DBG(10, "update_ranges: new_width = %d, new_height = %d\n",
new_width, new_height);
(*((SANE_Range *)(cs->opt[OPT_TL_X].constraint.range))).max =
new_width - 1;
(*((SANE_Range *)(cs->opt[OPT_TL_Y].constraint.range))).max =
new_height - 1;
(*((SANE_Range *)(cs->opt[OPT_BR_X].constraint.range))).max =
new_width;
(*((SANE_Range *)(cs->opt[OPT_BR_Y].constraint.range))).max =
new_height;
if (cs->vals[OPT_TL_X] > cs->opt[OPT_TL_X].constraint.range->max)
cs->vals[OPT_TL_X] = cs->opt[OPT_TL_X].constraint.range->max;
if (cs->vals[OPT_BR_X] > cs->opt[OPT_BR_X].constraint.range->max)
cs->vals[OPT_BR_X] = cs->opt[OPT_BR_X].constraint.range->max;
if (cs->vals[OPT_TL_Y] > cs->opt[OPT_TL_Y].constraint.range->max)
cs->vals[OPT_TL_Y] = cs->opt[OPT_TL_Y].constraint.range->max;
if (cs->vals[OPT_BR_Y] > cs->opt[OPT_BR_Y].constraint.range->max)
cs->vals[OPT_BR_Y] = cs->opt[OPT_BR_Y].constraint.range->max;
}
/*************************************************************************
*
* init_cal(): Try to create a calibration file
* has to be changed.
*
************************************************************************/
static int init_cal(char *file)
{
char *tmp, *path;
int f, i;
if ((f = open(file, O_CREAT | O_WRONLY, 0600)) < 0)
{
if (errno == ENOENT)
{
/* we need to try and make ~/.sane perhaps -
* find the last / in the file path, and try
* to create it */
if ((tmp = strrchr(file, '/')) == NULL)
return -1;
path = strdup(file);
*(path + (tmp-file)) = '\0';
i = mkdir(path, 0777);
free(path);
if (i) return -1;
/* Path has been created, now try this again.. */
if ((f = open(file, O_CREAT | O_WRONLY, 0600)) < 0)
return -1;
}
else
{
/* Error is something like access denied - too
* hard to fix, so i give up... */
return -1;
}
}
/* should probably set defaults here.. */
close(f);
return 0;
}
/*************************************************************************
*
* fix_weights_file(): Ensures that the weights_file setting for a given
* scanner is valid
*
************************************************************************/
static SANE_Status fix_weights_file(CANONP_Scanner *cs)
{
char *tmp, *myhome, buf[PATH_MAX];
int i;
struct stat *f_stat;
if (cs == NULL)
{
DBG(0, "fix_weights_file: FATAL: NULL passed by my code, "
"please report this!\n");
return SANE_STATUS_INVAL;
}
/* Assume this is false and then correct it */
cs->cal_readonly = SANE_FALSE;
if (cs->weights_file == NULL)
{
/* Will be of form canon_pp-calibration-parport0 or -0x378 */
sprintf(buf, "~/.sane/canon_pp-calibration-%s",
cs->params.port->name);
cs->weights_file = strdup(buf);
}
/* Get the user's home dir if they used ~ */
if (cs->weights_file[0] == '~')
{
if ((tmp = malloc(PATH_MAX)) == NULL)
return SANE_STATUS_NO_MEM;
if ((myhome = getenv("HOME")) == NULL)
{
DBG(0,"fix_weights_file: FATAL: ~ used, but $HOME not"
" set!\n");
free(tmp);
tmp = NULL;
return SANE_STATUS_INVAL;
}
strncpy(tmp, myhome, PATH_MAX);
strncpy(tmp+strlen(tmp), (cs->weights_file)+1,
PATH_MAX-strlen(tmp));
free(cs->weights_file);
cs->weights_file = tmp;
}
if ((f_stat = malloc(sizeof(struct stat))) == NULL)
return SANE_STATUS_NO_MEM;
if(stat(cs->weights_file, f_stat))
{
/* this non-intuitive if basically is if we got some error that
* wasn't no-such-file, or we can't create the file.. */
if ((errno != ENOENT) || init_cal(cs->weights_file))
{
/* Some nasty error returned. Give up. */
DBG(2,"fix_weights_file: error stating cal file"
" (%s)\n", strerror(errno));
DBG(2,"fix_weights_file: Changes to cal data won't"
" be saved!\n");
free(cs->weights_file);
cs->weights_file = NULL;
}
}
else
{
free(f_stat);
f_stat = NULL;
/* No error returned.. Check read/writability */
i = open(cs->weights_file, O_RDWR | O_APPEND);
if (i <= 0)
{
DBG(10,"fix_weighs_file: Note: Changes to cal data "
"won't be saved!\n");
i = open(cs->weights_file, O_RDONLY);
if (i <= 0)
{
/*
* Open failed (do i care why?)
*/
DBG(2,"fix_weights_file: error opening cal "
"(%s)\n", strerror(errno));
free(cs->weights_file);
cs->weights_file = NULL;
}
else
{
DBG(2,"fix_weights_file: file is read-only, "
"changes won't be saved\n");
cs->cal_readonly = SANE_TRUE;
close(i);
}
}
else
{
/* good! */
DBG(10,"fix_weights_file: Calibration file is good "
"for opening!\n");
close(i);
}
}
return SANE_STATUS_GOOD;
}
/* detect_mode
* PRE:
* cs->params.port is not open
* POST:
* cs->params.port is left opened iff SANE_STATUS_GOOD returned.
*/
SANE_Status detect_mode(CANONP_Scanner *cs)
{
int capabilities, tmp;
/* Open then claim parallel port using libieee1284 */
DBG(10,"detect_mode: Opening port %s\n", (cs->params.port->name));
tmp = ieee1284_open(cs->params.port, 0, &capabilities);
if (tmp != E1284_OK)
{
switch (tmp)
{
case E1284_INVALIDPORT:
DBG(1, "detect_mode: Invalid port.\n");
break;
case E1284_SYS:
DBG(1, "detect_mode: System error: %s\n",
strerror(errno));
break;
case E1284_INIT:
DBG(1, "detect_mode: Initialisation error.\n");
break;
default:
DBG(1, "detect_mode: Unknown error.\n");
break;
}
return SANE_STATUS_IO_ERROR;
}
DBG(10,"detect_mode: Claiming port.\n");
if (ieee1284_claim(cs->params.port) != E1284_OK)
{
DBG(1,"detect_mode: Unable to claim port\n");
ieee1284_close(cs->params.port);
return SANE_STATUS_IO_ERROR;
}
/* Check that compatibility-mode (required) is supported */
if (!(capabilities & CAP1284_COMPAT))
{
DBG(0,"detect_mode: Compatibility mode (required) not "
"supported.\n");
ieee1284_release(cs->params.port);
ieee1284_close(cs->params.port);
return SANE_STATUS_IO_ERROR;
}
/* Check capabilities which will enchance speed */
if (capabilities & CAP1284_ECP)
DBG(2, "detect_mode: Port supports ECP-H.\n");
else if (capabilities & CAP1284_ECPSWE)
DBG(2, "detect_mode: Port supports ECP-S.\n");
if (capabilities & CAP1284_IRQ)
DBG(2, "detect_mode: Port supports interrupts.\n");
if (capabilities & CAP1284_DMA)
DBG(2, "detect_mode: Port supports DMA.\n");
/* Check whether ECP mode is possible */
if (capabilities & CAP1284_ECP)
{
cs->ieee1284_mode = M1284_ECP;
DBG(10, "detect_mode: Using ECP-H Mode\n");
}
else if (capabilities & CAP1284_ECPSWE)
{
cs->ieee1284_mode = M1284_ECPSWE;
DBG(10, "detect_mode: Using ECP-S Mode\n");
}
else if (capabilities & CAP1284_NIBBLE)
{
cs->ieee1284_mode = M1284_NIBBLE;
DBG(10, "detect_mode: Using nibble mode\n");
}
else
{
DBG(0, "detect_mode: No supported parport modes available!\n");
ieee1284_release(cs->params.port);
ieee1284_close(cs->params.port);
return SANE_STATUS_IO_ERROR;
}
/* Check to make sure ECP mode really is supported */
if ((cs->ieee1284_mode == M1284_ECP) ||
(cs->ieee1284_mode == M1284_ECPSWE))
{
if (ieee1284_ecp_read_data(cs->params.port, 0, NULL, 0) ==
E1284_NOTIMPL)
{
DBG(10, "detect_mode: Your version of libieee1284 "
"doesn't support ECP mode - defaulting"
" to nibble mode instead.\n");
cs->ieee1284_mode = M1284_NIBBLE;
}
}
if (force_nibble == SANE_TRUE) {
DBG(10, "detect_mode: Nibble mode force in effect.\n");
cs->ieee1284_mode = M1284_NIBBLE;
}
ieee1284_release(cs->params.port);
sanei_canon_pp_set_ieee1284_mode(cs->ieee1284_mode);
return SANE_STATUS_GOOD;
}