From ffa8801644a7d53cc1c785e3450f794c07a14eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sun, 2 Feb 2020 17:13:01 +0100 Subject: New upstream version 1.0.29 --- backend/pixma.c | 2168 ------------------------------------------------------- 1 file changed, 2168 deletions(-) delete mode 100644 backend/pixma.c (limited to 'backend/pixma.c') diff --git a/backend/pixma.c b/backend/pixma.c deleted file mode 100644 index d33a74e..0000000 --- a/backend/pixma.c +++ /dev/null @@ -1,2168 +0,0 @@ -/* SANE - Scanner Access Now Easy. - - Copyright (C) 2011-2019 Rolf Bensch - Copyright (C) 2007-2008 Nicolas Martin, - Copyright (C) 2006-2007 Wittawat Yamwong - - 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. - */ -#include "../include/sane/config.h" - -#include -#include -#include -#ifdef USE_PTHREAD -# include -#endif -#include /* sigaction(POSIX) */ -#include /* POSIX: write read close pipe */ -#ifdef HAVE_FCNTL_H -# include -#endif - -#include "pixma_rename.h" -#include "pixma.h" - -# define DEBUG_NOT_STATIC -# include "../include/sane/sane.h" -# include "../include/sane/sanei.h" -# include "../include/sane/saneopts.h" -# include "../include/sane/sanei_thread.h" -# include "../include/sane/sanei_backend.h" -# include "../include/sane/sanei_config.h" -# include "../include/sane/sanei_jpeg.h" - -#ifdef NDEBUG -# define PDBG(x) -#else -# define PDBG(x) IF_DBG(x) -#endif /* NDEBUG */ - -#ifdef __GNUC__ -# define UNUSED(v) (void) v -#else -# define UNUSED(v) -#endif - -#define DECL_CTX pixma_sane_t *ss = check_handle(h) -#define OPT_IN_CTX ss->opt -#define SOD(opt) OPT_IN_CTX[opt].sod -#define OVAL(opt) OPT_IN_CTX[opt].val -#define AUTO_GAMMA 2.2 - -/* pixma_sane_options.h generated by - * scripts/pixma_gen_options.py h < pixma.c > pixma_sane_options.h - */ -#include "pixma_sane_options.h" - -#define BUTTON_GROUP_SIZE ( opt_scan_resolution - opt_button_1 + 1 ) -#define BUTTON_GROUP_INDEX(x) ( x - opt_button_1 ) - -typedef struct pixma_sane_t -{ - struct pixma_sane_t *next; - pixma_t *s; - pixma_scan_param_t sp; - SANE_Bool cancel; - - /* valid states: idle, !idle && scanning, !idle && !scanning */ - SANE_Bool idle; - SANE_Bool scanning; - SANE_Status last_read_status; /* valid if !idle && !scanning */ - - option_descriptor_t opt[opt_last]; - char button_option_is_cached[BUTTON_GROUP_SIZE]; - SANE_Range xrange, yrange; - SANE_Word dpi_list[9]; /* up to 9600 dpi */ - SANE_String_Const mode_list[6]; - pixma_scan_mode_t mode_map[6]; - uint8_t gamma_table[4096]; - SANE_String_Const source_list[4]; - pixma_paper_source_t source_map[4]; - - unsigned byte_pos_in_line, output_line_size; - uint64_t image_bytes_read; - unsigned page_count; /* valid for ADF */ - - SANE_Pid reader_taskid; - int wpipe, rpipe; - SANE_Bool reader_stop; - - /* Valid for JPEG source */ - djpeg_dest_ptr jdst; - struct jpeg_decompress_struct jpeg_cinfo; - struct jpeg_error_mgr jpeg_err; - SANE_Bool jpeg_header_seen; -} pixma_sane_t; - -typedef struct -{ - struct jpeg_source_mgr jpeg; - - pixma_sane_t *s; - JOCTET *buffer; - - SANE_Byte *linebuffer; - SANE_Int linebuffer_size; - SANE_Int linebuffer_index; -} pixma_jpeg_src_mgr; - - -static const char vendor_str[] = "CANON"; -static const char type_str[] = "multi-function peripheral"; - -static pixma_sane_t *first_scanner = NULL; -static const SANE_Device **dev_list = NULL; -static const char* conf_devices[MAX_CONF_DEVICES]; - -static void mark_all_button_options_cached ( struct pixma_sane_t * ss ) -{ - int i; - for (i = 0; i < (opt__group_5 - opt_button_1); i++ ) - ss -> button_option_is_cached[i] = 1; -} - -static SANE_Status config_attach_pixma(SANEI_Config * config, const char *devname) -{ - int i; - UNUSED(config); - for (i=0; i < (MAX_CONF_DEVICES -1); i++) - { - if(conf_devices[i] == NULL) - { - conf_devices[i] = strdup(devname); - return SANE_STATUS_GOOD; - } - } - return SANE_STATUS_INVAL; -} - -static SANE_Status -map_error (int error) -{ - if (error >= 0) - return SANE_STATUS_GOOD; - - switch (error) - { - case PIXMA_ENOMEM: - return SANE_STATUS_NO_MEM; - case PIXMA_ECANCELED: - return SANE_STATUS_CANCELLED; - case PIXMA_EBUSY: - return SANE_STATUS_DEVICE_BUSY; - case PIXMA_EINVAL: - return SANE_STATUS_INVAL; - case PIXMA_EACCES: - return SANE_STATUS_ACCESS_DENIED; - case PIXMA_EPAPER_JAMMED: - return SANE_STATUS_JAMMED; - case PIXMA_ENO_PAPER: - return SANE_STATUS_NO_DOCS; - case PIXMA_ECOVER_OPEN: - return SANE_STATUS_COVER_OPEN; - case PIXMA_ENOTSUP: - return SANE_STATUS_UNSUPPORTED; - case PIXMA_EPROTO: - case PIXMA_ENODEV: - case PIXMA_EIO: - case PIXMA_ETIMEDOUT: - return SANE_STATUS_IO_ERROR; - } - PDBG (pixma_dbg (1, "BUG: unmapped error %d\n", error)); - return SANE_STATUS_IO_ERROR; -} - -static int -getenv_atoi (const char *name, int def) -{ - const char *str = getenv (name); - return (str) ? atoi (str) : def; -} - -#define CONST_CAST(t,x) (t)(x) - -static void -free_block (const void * ptr) -{ - free (CONST_CAST (void *, ptr)); -} - -static void -cleanup_device_list (void) -{ - if (dev_list) - { - int i; - for (i = 0; dev_list[i]; i++) - { - free_block ((const void *) dev_list[i]->name); - free_block ((const void *) dev_list[i]->model); - free_block ((const void *) dev_list[i]); - } - } - free (dev_list); - dev_list = NULL; -} - -static void -find_scanners (void) -{ - unsigned i, nscanners; - - cleanup_device_list (); - nscanners = pixma_find_scanners (conf_devices); - PDBG (pixma_dbg (3, "pixma_find_scanners() found %u devices\n", nscanners)); - dev_list = - (const SANE_Device **) calloc (nscanners + 1, sizeof (*dev_list)); - if (!dev_list) - return; - for (i = 0; i != nscanners; i++) - { - SANE_Device *sdev = (SANE_Device *) calloc (1, sizeof (*sdev)); - char *name, *model; - if (!sdev) - goto nomem; - name = strdup (pixma_get_device_id (i)); - model = strdup (pixma_get_device_model (i)); - if (!name || !model) - { - free (name); - free (model); - free (sdev); - goto nomem; - } - sdev->name = name; - sdev->model = model; - sdev->vendor = vendor_str; - sdev->type = type_str; - dev_list[i] = sdev; - } - /* dev_list is already NULL terminated by calloc(). */ - return; - -nomem: - PDBG (pixma_dbg (1, "WARNING:not enough memory for device list\n")); - return; -} - -static pixma_sane_t * -check_handle (SANE_Handle h) -{ - pixma_sane_t *p; - - for (p = first_scanner; p && (SANE_Handle) p != h; p = p->next) - { - } - return p; -} - -static void -update_button_state (pixma_sane_t * ss, SANE_Int * info) -{ - SANE_Int b1 = OVAL (opt_button_1).w; - SANE_Int b2 = OVAL (opt_button_2).w; - uint32_t ev = pixma_wait_event (ss->s, 300); - switch (ev & ~PIXMA_EV_ACTION_MASK) - { - case PIXMA_EV_BUTTON1: - b1 = 1; - break; - case PIXMA_EV_BUTTON2: - b2 = 1; - break; - } - - if (b1 != OVAL (opt_button_1).w || b2 != OVAL (opt_button_2).w) - { - *info |= SANE_INFO_RELOAD_OPTIONS; - OVAL (opt_button_1).w = b1; - OVAL (opt_button_2).w = b2; - OVAL (opt_original).w = GET_EV_ORIGINAL(ev); - OVAL (opt_target).w = GET_EV_TARGET(ev); - OVAL (opt_scan_resolution).w = GET_EV_DPI(ev); - } - mark_all_button_options_cached(ss); -} - -static SANE_Bool -enable_option (pixma_sane_t * ss, SANE_Int o, SANE_Bool enable) -{ - SANE_Word save = SOD (o).cap; - if (enable) - SOD (o).cap &= ~SANE_CAP_INACTIVE; - else - SOD (o).cap |= SANE_CAP_INACTIVE; - return (save != SOD (o).cap); -} - -static void -clamp_value (pixma_sane_t * ss, SANE_Int n, void *v, SANE_Int * info) -{ - SANE_Option_Descriptor *sod = &SOD (n); - SANE_Word *va = (SANE_Word *) v; - const SANE_Range *range = sod->constraint.range; - int i, nmemb; - - nmemb = sod->size / sizeof (SANE_Word); - for (i = 0; i < nmemb; i++) - { - SANE_Word value = va[i]; - if (value < range->min) - { - value = range->min; - } - else if (value > range->max) - { - value = range->max; - } - if (range->quant != 0) - { - value = (value - range->min + range->quant / 2) / - range->quant * range->quant; - } - if (value != va[i]) - { - va[i] = value; - *info |= SANE_INFO_INEXACT; - } - } -} - -/* create dynamic mode_list - * ss: scanner device - * tpu = 0: flatbed or ADF mode - * 1 bit lineart, 8 bit grayscale and 24 bit color scans - * tpu = 1: TPU mode - * 16 bit grayscale and 48 bit color scans */ -static void -create_mode_list (pixma_sane_t * ss) -{ - SANE_Bool tpu; - const pixma_config_t *cfg; - int i; - - cfg = pixma_get_config (ss->s); - tpu = (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU); - - /* setup available mode */ - i = 0; - ss->mode_list[i] = SANE_VALUE_SCAN_MODE_COLOR; - ss->mode_map[i] = PIXMA_SCAN_MODE_COLOR; - i++; - if (cfg->cap & PIXMA_CAP_GRAY) - { - ss->mode_list[i] = SANE_VALUE_SCAN_MODE_GRAY; - ss->mode_map[i] = PIXMA_SCAN_MODE_GRAY; - i++; - } - if (tpu && (cfg->cap & PIXMA_CAP_NEGATIVE)) - { - ss->mode_list[i] = SANE_I18N ("Negative color"); - ss->mode_map[i] = PIXMA_SCAN_MODE_NEGATIVE_COLOR; - i++; - if (cfg->cap & PIXMA_CAP_GRAY) - { - ss->mode_list[i] = SANE_I18N ("Negative gray"); - ss->mode_map[i] = PIXMA_SCAN_MODE_NEGATIVE_GRAY; - i++; - } - } - if (tpu && (cfg->cap & PIXMA_CAP_TPUIR) == PIXMA_CAP_TPUIR) - { - ss->mode_list[i] = SANE_I18N ("Infrared"); - ss->mode_map[i] = PIXMA_SCAN_MODE_TPUIR; - i++; - } - if (!tpu && (cfg->cap & PIXMA_CAP_48BIT)) - { - ss->mode_list[i] = SANE_I18N ("48 bits color"); - ss->mode_map[i] = PIXMA_SCAN_MODE_COLOR_48; - i++; - if (cfg->cap & PIXMA_CAP_GRAY) - { - ss->mode_list[i] = SANE_I18N ("16 bits gray"); - ss->mode_map[i] = PIXMA_SCAN_MODE_GRAY_16; - i++; - } - } - if (!tpu && (cfg->cap & PIXMA_CAP_LINEART)) - { - ss->mode_list[i] = SANE_VALUE_SCAN_MODE_LINEART; - ss->mode_map[i] = PIXMA_SCAN_MODE_LINEART; - i++; - } - /* terminate mode_list and mode_map */ - ss->mode_list[i] = 0; - ss->mode_map[i] = 0; -} - -/* create dynamic dpi_list - * ss: scanner device */ -static void -create_dpi_list (pixma_sane_t * ss) -{ - const pixma_config_t *cfg; - int i, j; - int min; - unsigned min_dpi; - unsigned max_dpi; - - cfg = pixma_get_config (ss->s); - - /* get min/max dpi */ - max_dpi = cfg->xdpi; - min_dpi = 75; - if (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU - && ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_TPUIR) - { /* IR mode */ - /*PDBG (pixma_dbg (4, "*create_dpi_list***** TPUIR mode\n"));*/ - min_dpi = (cfg->tpuir_min_dpi) ? cfg->tpuir_min_dpi : 75; - max_dpi = (cfg->tpuir_max_dpi) ? cfg->tpuir_max_dpi : cfg->xdpi; - } - else if (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU - || ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_ADF - || ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_ADFDUP) - { /* ADF / TPU mode */ - /*PDBG (pixma_dbg (4, "*create_dpi_list***** ADF/TPU mode\n"));*/ - min_dpi = (cfg->adftpu_min_dpi) ? cfg->adftpu_min_dpi : 75; - max_dpi = (cfg->adftpu_max_dpi) ? cfg->adftpu_max_dpi : cfg->xdpi; - } - else if (ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_FLATBED - && (ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_COLOR_48 - || ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_GRAY_16)) - { /* 48 bits flatbed */ - /*PDBG (pixma_dbg (4, "*create_dpi_list***** 48 bits flatbed mode\n"));*/ - min_dpi = 150; - } - - /* set j for min. dpi - * 75 dpi: j = 0 - * 150 dpi: j = 1 \ - * 300 dpi: j = 2 |--> from cfg->adftpu_min_dpi or cfg->tpuir_min_dpi - * 600 dpi: j = 3 / - * */ - j = -1; - min = min_dpi / 75; - do - { - j++; - min >>= 1; - } - while (min > 0); - - /* create dpi_list - * use j for min. dpi */ - i = 0; - do - { - i++; j++; - ss->dpi_list[i] = 75 * (1 << (j - 1)); /* 75 x 2^(j-1) */ - } - while ((unsigned) ss->dpi_list[i] < max_dpi); - ss->dpi_list[0] = i; - /*PDBG (pixma_dbg (4, "*create_dpi_list***** min_dpi = %d, max_dpi = %d\n", min_dpi, max_dpi));*/ -} - -static void -select_value_from_list (pixma_sane_t * ss, SANE_Int n, void *v, - SANE_Int * info) -{ - SANE_Option_Descriptor *sod = &SOD (n); - SANE_Word *va = (SANE_Word *) v; - const SANE_Word *list = sod->constraint.word_list; - int i, j, nmemb; - - nmemb = sod->size / sizeof (SANE_Word); - for (i = 0; i < nmemb; i++) - { - SANE_Word value = va[i]; - SANE_Word mindelta = abs (value - list[1]); - SANE_Word nearest = list[1]; - for (j = 2; j <= list[0]; j++) - { - SANE_Word delta = abs (value - list[j]); - if (delta < mindelta) - { - mindelta = delta; - nearest = list[j]; - } - if (mindelta == 0) - break; - } - if (va[i] != nearest) - { - va[i] = nearest; - *info |= SANE_INFO_INEXACT; - } - } -} - -static SANE_Status -control_scalar_option (pixma_sane_t * ss, SANE_Int n, SANE_Action a, void *v, - SANE_Int * info) -{ - option_descriptor_t *opt = &(OPT_IN_CTX[n]); - SANE_Word val; - - switch (a) - { - case SANE_ACTION_GET_VALUE: - switch (opt->sod.type) - { - case SANE_TYPE_BOOL: - case SANE_TYPE_INT: - case SANE_TYPE_FIXED: - *(SANE_Word *) v = opt->val.w; - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - return SANE_STATUS_GOOD; - - case SANE_ACTION_SET_VALUE: - switch (opt->sod.type) - { - case SANE_TYPE_BOOL: - val = *(SANE_Word *) v; - if (val != SANE_TRUE && val != SANE_FALSE) - return SANE_STATUS_INVAL; - opt->val.w = val; - break; - case SANE_TYPE_INT: - case SANE_TYPE_FIXED: - if (opt->sod.constraint_type == SANE_CONSTRAINT_RANGE) - clamp_value (ss, n, v, info); - else if (opt->sod.constraint_type == SANE_CONSTRAINT_WORD_LIST) - select_value_from_list (ss, n, v, info); - opt->val.w = *(SANE_Word *) v; - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - *info |= opt->info; - return SANE_STATUS_GOOD; - - case SANE_ACTION_SET_AUTO: - switch (opt->sod.type) - { - case SANE_TYPE_BOOL: - case SANE_TYPE_INT: - case SANE_TYPE_FIXED: - opt->val.w = opt->def.w; - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - *info |= opt->info; - return SANE_STATUS_GOOD; - } - return SANE_STATUS_UNSUPPORTED; -} - -static SANE_Status -control_string_option (pixma_sane_t * ss, SANE_Int n, SANE_Action a, void *v, - SANE_Int * info) -{ - option_descriptor_t *opt = &(OPT_IN_CTX[n]); - const SANE_String_Const *slist = opt->sod.constraint.string_list; - SANE_String str = (SANE_String) v; - - if (opt->sod.constraint_type == SANE_CONSTRAINT_NONE) - { - switch (a) - { - case SANE_ACTION_GET_VALUE: - strcpy (str, opt->val.s); - break; - case SANE_ACTION_SET_AUTO: - str = opt->def.s; - /* fall through */ - case SANE_ACTION_SET_VALUE: - strncpy (opt->val.s, str, opt->sod.size - 1); - *info |= opt->info; - break; - } - return SANE_STATUS_GOOD; - } - else - { - int i; - - switch (a) - { - case SANE_ACTION_GET_VALUE: - strcpy (str, slist[opt->val.w]); - break; - case SANE_ACTION_SET_AUTO: - str = opt->def.ptr; - /* fall through */ - case SANE_ACTION_SET_VALUE: - i = 0; - while (slist[i] && strcasecmp (str, slist[i]) != 0) - i++; - if (!slist[i]) - return SANE_STATUS_INVAL; - if (strcmp (slist[i], str) != 0) - { - strcpy (str, slist[i]); - *info |= SANE_INFO_INEXACT; - } - opt->val.w = i; - *info |= opt->info; - break; - } - return SANE_STATUS_GOOD; - } -} - -static SANE_Status -control_option (pixma_sane_t * ss, SANE_Int n, - SANE_Action a, void *v, SANE_Int * info) -{ - int result, i; - const pixma_config_t *cfg; - SANE_Int dummy; - - /* info may be null, better to set a dummy here then test everywhere */ - if (info == NULL) - info = &dummy; - - cfg = pixma_get_config (ss->s); - - /* PDBG (pixma_dbg (4, "*control_option***** n = %u, a = %u\n", n, a)); */ - - /* first deal with options that require special treatment */ - result = SANE_STATUS_UNSUPPORTED; - switch (n) - { - case opt_gamma_table: - switch (a) - { - case SANE_ACTION_SET_VALUE: - clamp_value (ss, n, v, info); - for (i = 0; i != 4096; i++) - ss->gamma_table[i] = *((SANE_Int *) v + i); - break; - case SANE_ACTION_GET_VALUE: - for (i = 0; i != 4096; i++) - *((SANE_Int *) v + i) = ss->gamma_table[i]; - break; - case SANE_ACTION_SET_AUTO: - pixma_fill_gamma_table (AUTO_GAMMA, ss->gamma_table, - sizeof (ss->gamma_table)); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - return SANE_STATUS_GOOD; - - case opt_button_update: - if (a == SANE_ACTION_SET_VALUE) - { - update_button_state (ss, info); - return SANE_STATUS_GOOD; - } - else - { - return SANE_STATUS_INVAL; - } - break; - case opt_button_1: - case opt_button_2: - case opt_original: - case opt_target: - case opt_scan_resolution: - /* poll scanner if option is not cached */ - if (! ss->button_option_is_cached[ BUTTON_GROUP_INDEX(n) ] ) - update_button_state (ss, info); - /* mark this option as read */ - ss->button_option_is_cached[ BUTTON_GROUP_INDEX(n) ] = 0; - } - - /* now deal with getting and setting of options */ - switch (SOD (n).type) - { - case SANE_TYPE_BOOL: - case SANE_TYPE_INT: - case SANE_TYPE_FIXED: - result = control_scalar_option (ss, n, a, v, info); - break; - case SANE_TYPE_STRING: - result = control_string_option (ss, n, a, v, info); - break; - case SANE_TYPE_BUTTON: - case SANE_TYPE_GROUP: - PDBG (pixma_dbg (1, "BUG:control_option():Unhandled option\n")); - result = SANE_STATUS_INVAL; - break; - } - if (result != SANE_STATUS_GOOD) - return result; - - /* deal with dependencies between options */ - switch (n) - { - case opt_custom_gamma: - if (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO) - { - if (enable_option (ss, opt_gamma_table, OVAL (opt_custom_gamma).b)) - *info |= SANE_INFO_RELOAD_OPTIONS; - } - break; - case opt_gamma: - if (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO) - { - /* PDBG (pixma_dbg (4, "*control_option***** gamma = %f *\n", - SANE_UNFIX (OVAL (opt_gamma).w))); */ - pixma_fill_gamma_table (SANE_UNFIX (OVAL (opt_gamma).w), - ss->gamma_table, sizeof (ss->gamma_table)); - } - break; - case opt_mode: - if (cfg->cap & (PIXMA_CAP_48BIT|PIXMA_CAP_LINEART|PIXMA_CAP_TPUIR) - && (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO)) - { /* new mode selected: Color, Gray, ... */ - /* PDBG (pixma_dbg (4, "*control_option***** mode = %u *\n", - ss->mode_map[OVAL (opt_mode).w])); */ - /* recreate dynamic lists */ - create_dpi_list (ss); - if (ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_LINEART) - { /* lineart */ - enable_option (ss, opt_threshold, SANE_TRUE); - enable_option (ss, opt_threshold_curve, SANE_TRUE); - } - else - { /* all other modes */ - enable_option (ss, opt_threshold, SANE_FALSE); - enable_option (ss, opt_threshold_curve, SANE_FALSE); - } - *info |= SANE_INFO_RELOAD_OPTIONS; - } - break; - case opt_source: - if ((cfg->cap & (PIXMA_CAP_ADF|PIXMA_CAP_ADFDUP|PIXMA_CAP_TPU)) - && (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO)) - { /* new source selected: flatbed, ADF, TPU, ... */ - /* to avoid fatal errors, - * select first entry of dynamic mode_list - * identifiers are unknown here */ - OVAL (opt_mode).w = ss->mode_map[0]; - /* recreate dynamic lists */ - create_mode_list (ss); - create_dpi_list (ss); - /* to avoid fatal errors, - * select first entry of dynamic dpi_list - * identifiers are unknown here */ - OVAL (opt_resolution).w = ss->dpi_list[1]; - if (ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_LINEART) - { /* lineart */ - enable_option (ss, opt_threshold, SANE_TRUE); - enable_option (ss, opt_threshold_curve, SANE_TRUE); - } - else - { /* all other modes */ - enable_option (ss, opt_threshold, SANE_FALSE); - enable_option (ss, opt_threshold_curve, SANE_FALSE); - } - if (cfg->cap & (PIXMA_CAP_ADF_WAIT)) - { /* adf-wait */ - enable_option (ss, opt_adf_wait, SANE_TRUE); - } - else - { /* disable adf-wait */ - enable_option (ss, opt_adf_wait, SANE_FALSE); - } - *info |= SANE_INFO_RELOAD_OPTIONS; - } - break; - } - - return result; -} - -#ifndef NDEBUG -static void -print_scan_param (int level, const pixma_scan_param_t * sp) -{ - pixma_dbg (level, "Scan parameters\n"); - pixma_dbg (level, " line_size=%"PRIu64" image_size=%"PRIu64" channels=%u depth=%u\n", - sp->line_size, sp->image_size, sp->channels, sp->depth); - pixma_dbg (level, " dpi=%ux%u offset=(%u,%u) dimension=%ux%u\n", - sp->xdpi, sp->ydpi, sp->x, sp->y, sp->w, sp->h); - pixma_dbg (level, " gamma_table=%p source=%d\n", sp->gamma_table, - sp->source); - pixma_dbg (level, " adf-wait=%d\n", sp->adf_wait); -} -#endif - -static int -calc_scan_param (pixma_sane_t * ss, pixma_scan_param_t * sp) -{ - int x1, y1, x2, y2; - int error; - - memset (sp, 0, sizeof (*sp)); - - sp->channels = (OVAL (opt_mode).w == 0) ? 3 : 1; - sp->depth = (OVAL (opt_mode).w == 2) ? 1 : 8; - sp->xdpi = sp->ydpi = OVAL (opt_resolution).w; - -#define PIXEL(x,dpi) (int)((SANE_UNFIX(x) / 25.4 * (dpi)) + 0.5) - x1 = PIXEL (OVAL (opt_tl_x).w, sp->xdpi); - x2 = PIXEL (OVAL (opt_br_x).w, sp->xdpi); - if (x2 < x1) - { - int temp = x1; - x1 = x2; - x2 = temp; - } - y1 = PIXEL (OVAL (opt_tl_y).w, sp->ydpi); - y2 = PIXEL (OVAL (opt_br_y).w, sp->ydpi); - if (y2 < y1) - { - int temp = y1; - y1 = y2; - y2 = temp; - } -#undef PIXEL - sp->x = x1; - sp->y = y1; - sp->w = x2 - x1; - sp->h = y2 - y1; - if (sp->w == 0) - sp->w = 1; - if (sp->h == 0) - sp->h = 1; - sp->tpu_offset_added = 0; - - sp->gamma_table = (OVAL (opt_custom_gamma).b) ? ss->gamma_table : NULL; - sp->source = ss->source_map[OVAL (opt_source).w]; - sp->mode = ss->mode_map[OVAL (opt_mode).w]; - sp->adf_pageid = ss->page_count; - sp->threshold = 2.55 * OVAL (opt_threshold).w; - sp->threshold_curve = OVAL (opt_threshold_curve).w; - sp->adf_wait = OVAL (opt_adf_wait).w; - - error = pixma_check_scan_param (ss->s, sp); - if (error < 0) - { - PDBG (pixma_dbg (1, "BUG:calc_scan_param() failed %d\n", error)); - PDBG (print_scan_param (1, sp)); - } - return error; -} - -static void -init_option_descriptors (pixma_sane_t * ss) -{ - const pixma_config_t *cfg; - int i; - - cfg = pixma_get_config (ss->s); - - /* setup range for the scan area. */ - ss->xrange.min = SANE_FIX (0); - ss->xrange.max = SANE_FIX (cfg->width / 75.0 * 25.4); - ss->xrange.quant = SANE_FIX (0); - - ss->yrange.min = SANE_FIX (0); - ss->yrange.max = SANE_FIX (cfg->height / 75.0 * 25.4); - ss->yrange.quant = SANE_FIX (0); - - /* mode_list and source_list were already NULL-terminated, - * because the whole pixma_sane_t was cleared during allocation. */ - - /* setup available mode. */ - create_mode_list (ss); - - /* setup dpi up to the value supported by the scanner. */ - create_dpi_list (ss); - - /* setup paper source */ - i = 0; - ss->source_list[i] = SANE_I18N ("Flatbed"); - ss->source_map[i] = PIXMA_SOURCE_FLATBED; - i++; - if (cfg->cap & PIXMA_CAP_ADF) - { - ss->source_list[i] = SANE_I18N ("Automatic Document Feeder"); - ss->source_map[i] = PIXMA_SOURCE_ADF; - i++; - } - if ((cfg->cap & PIXMA_CAP_ADFDUP) == PIXMA_CAP_ADFDUP) - { - ss->source_list[i] = SANE_I18N ("ADF Duplex"); - ss->source_map[i] = PIXMA_SOURCE_ADFDUP; - i++; - } - if (cfg->cap & PIXMA_CAP_TPU) - { - ss->source_list[i] = SANE_I18N ("Transparency Unit"); - ss->source_map[i] = PIXMA_SOURCE_TPU; - i++; - } - - build_option_descriptors (ss); - - /* Enable options that are available only in some scanners. */ - if (cfg->cap & PIXMA_CAP_GAMMA_TABLE) - { - enable_option (ss, opt_gamma, SANE_TRUE); - enable_option (ss, opt_custom_gamma, SANE_TRUE); - sane_control_option (ss, opt_custom_gamma, SANE_ACTION_SET_AUTO, - NULL, NULL); - pixma_fill_gamma_table (AUTO_GAMMA, ss->gamma_table, 4096); - } - enable_option (ss, opt_button_controlled, - ((cfg->cap & PIXMA_CAP_EVENTS) != 0)); -} - -/* Writing to reader_ss outside reader_process() is a BUG! */ -static pixma_sane_t *reader_ss = NULL; - -static void -reader_signal_handler (int sig) -{ - if (reader_ss) - { - reader_ss->reader_stop = SANE_TRUE; - /* reader process is ended by SIGTERM, so no cancel in this case */ - if (sig != SIGTERM) - pixma_cancel (reader_ss->s); - } -} - -static int -write_all (pixma_sane_t * ss, void *buf_, size_t size) -{ - uint8_t *buf = (uint8_t *) buf_; - int count; - - while (size != 0 && !ss->reader_stop) - { - count = write (ss->wpipe, buf, size); - if (count == -1 && errno != EINTR) - break; - if (count == -1 && errno == EINTR) - continue; - buf += count; - size -= count; - } - return buf - (uint8_t *) buf_; -} - -/* NOTE: reader_loop() runs either in a separate thread or process. */ -static SANE_Status -reader_loop (pixma_sane_t * ss) -{ - void *buf; - unsigned bufsize; - int count = 0; - - PDBG (pixma_dbg (3, "Reader task started\n")); - /*bufsize = ss->sp.line_size + 1;*/ /* XXX: "odd" bufsize for testing pixma_read_image() */ - bufsize = ss->sp.line_size; /* bufsize EVEN needed by Xsane for 48 bits depth */ - buf = malloc (bufsize); - if (!buf) - { - count = PIXMA_ENOMEM; - goto done; - } - - count = pixma_activate_connection (ss->s); - if (count < 0) - goto done; - - pixma_enable_background (ss->s, 1); - if (OVAL (opt_button_controlled).b && ss->page_count == 0) - { - int start = 0; -#ifndef NDEBUG - pixma_dbg (1, "==== Button-controlled scan mode is enabled.\n"); - pixma_dbg (1, "==== To proceed, press 'SCAN' or 'COLOR' button. " - "To cancel, press 'GRAY' or 'END' button.\n"); -#endif - while (pixma_wait_event (ss->s, 10) != 0) - { - } - while (!start) - { - uint32_t events; - if (ss->reader_stop) - { - count = PIXMA_ECANCELED; - goto done; - } - events = pixma_wait_event (ss->s, 1000); - switch (events & ~PIXMA_EV_ACTION_MASK) - { - case PIXMA_EV_BUTTON1: - start = 1; - break; - case PIXMA_EV_BUTTON2: - count = PIXMA_ECANCELED; - goto done; - } - } - } - count = pixma_scan (ss->s, &ss->sp); - if (count >= 0) - { - while ((count = pixma_read_image (ss->s, buf, bufsize)) > 0) - { - if (write_all (ss, buf, count) != count) - pixma_cancel (ss->s); - } - } - -done: - pixma_enable_background (ss->s, 0); - pixma_deactivate_connection (ss->s); - free (buf); - close (ss->wpipe); - ss->wpipe = -1; - if (count >= 0) - { - PDBG (pixma_dbg (3, "Reader task terminated\n")); - } - else - { - PDBG (pixma_dbg - (2, "Reader task terminated: %s\n", pixma_strerror (count))); - } - return map_error (count); -} - -static int -reader_process (void *arg) -{ - pixma_sane_t *ss = (pixma_sane_t *) arg; - struct SIGACTION sa; - - reader_ss = ss; - memset (&sa, 0, sizeof (sa)); - sigemptyset (&sa.sa_mask); - sa.sa_handler = reader_signal_handler; - /* FIXME: which signal else? */ - sigaction (SIGHUP, &sa, NULL); - sigaction (SIGINT, &sa, NULL); - sigaction (SIGPIPE, &sa, NULL); - sigaction (SIGTERM, &sa, NULL); - close (ss->rpipe); - ss->rpipe = -1; - return reader_loop (ss); -} - -static int -reader_thread (void *arg) -{ - pixma_sane_t *ss = (pixma_sane_t *) arg; -#ifdef USE_PTHREAD - /* Block SIGPIPE. We will handle this in reader_loop() by checking - ss->reader_stop and the return value from write(). */ - sigset_t sigs; - sigemptyset (&sigs); - sigaddset (&sigs, SIGPIPE); - pthread_sigmask (SIG_BLOCK, &sigs, NULL); -#endif /* USE_PTHREAD */ - return reader_loop (ss); -} - -static SANE_Pid -terminate_reader_task (pixma_sane_t * ss, int *exit_code) -{ - SANE_Pid result, pid; - int status = 0; - - pid = ss->reader_taskid; - if (!sanei_thread_is_valid (pid)) - return pid; - if (sanei_thread_is_forked ()) - { - sanei_thread_kill (pid); - } - else - { - ss->reader_stop = SANE_TRUE; -/* pixma_cancel (ss->s); What is this for ? Makes end-of-scan buggy => removing */ - } - result = sanei_thread_waitpid (pid, &status); - sanei_thread_invalidate (ss->reader_taskid); - - if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP) - ss->idle = SANE_TRUE; - - if (result == pid) - { - if (exit_code) - *exit_code = status; - return pid; - } - else - { - PDBG (pixma_dbg (1, "WARNING:waitpid() failed %s\n", strerror (errno))); - sanei_thread_invalidate (pid); - return pid; - } -} - -static int -start_reader_task (pixma_sane_t * ss) -{ - int fds[2]; - SANE_Pid pid; - int is_forked; - - if (ss->rpipe != -1 || ss->wpipe != -1) - { - PDBG (pixma_dbg - (1, "BUG:rpipe = %d, wpipe = %d\n", ss->rpipe, ss->wpipe)); - close (ss->rpipe); - close (ss->wpipe); - ss->rpipe = -1; - ss->wpipe = -1; - } - if (sanei_thread_is_valid (ss->reader_taskid)) - { - PDBG (pixma_dbg - (1, "BUG:reader_taskid(%ld) != -1\n", (long) ss->reader_taskid)); - terminate_reader_task (ss, NULL); - } - if (pipe (fds) == -1) - { - PDBG (pixma_dbg (1, "ERROR:start_reader_task():pipe() failed %s\n", - strerror (errno))); - return PIXMA_ENOMEM; - } - ss->rpipe = fds[0]; - ss->wpipe = fds[1]; - ss->reader_stop = SANE_FALSE; - - is_forked = sanei_thread_is_forked (); - if (is_forked) - { - pid = sanei_thread_begin (reader_process, ss); - if (sanei_thread_is_valid (pid)) - { - close (ss->wpipe); - ss->wpipe = -1; - } - } - else - { - pid = sanei_thread_begin (reader_thread, ss); - } - if (!sanei_thread_is_valid (pid)) - { - close (ss->wpipe); - close (ss->rpipe); - ss->wpipe = -1; - ss->rpipe = -1; - PDBG (pixma_dbg (1, "ERROR:unable to start reader task\n")); - return PIXMA_ENOMEM; - } - PDBG (pixma_dbg (3, "Reader task id=%ld (%s)\n", (long) pid, - (is_forked) ? "forked" : "threaded")); - ss->reader_taskid = pid; - return 0; -} - -/* libJPEG API callbacks */ -static void -jpeg_init_source(j_decompress_ptr __sane_unused__ cinfo) -{ - /* No-op */ -} - -static void -jpeg_term_source(j_decompress_ptr __sane_unused__ cinfo) -{ - /* No-op */ -} - -static boolean -jpeg_fill_input_buffer(j_decompress_ptr cinfo) -{ - pixma_jpeg_src_mgr *mgr = (pixma_jpeg_src_mgr *)cinfo->src; - int size; - int retry; - - for (retry = 0; retry < 30; retry ++ ) - { - size = read (mgr->s->rpipe, mgr->buffer, 1024); - if (size == 0) - { - return FALSE; - } - else if (size < 0) - { - sleep (1); - } - else - { - mgr->jpeg.next_input_byte = mgr->buffer; - mgr->jpeg.bytes_in_buffer = size; - return TRUE; - } - } - - return FALSE; -} - -static void -jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) -{ - pixma_jpeg_src_mgr *mgr = (pixma_jpeg_src_mgr *)cinfo->src; - - if (num_bytes > 0) - { - /* Read and throw away extra */ - while (num_bytes > (long)mgr->jpeg.bytes_in_buffer) - { - num_bytes -= (long)mgr->jpeg.bytes_in_buffer; - jpeg_fill_input_buffer(cinfo); - } - - /* Update jpeg info structure with leftover */ - mgr->jpeg.next_input_byte += (size_t) num_bytes; - mgr->jpeg.bytes_in_buffer -= (size_t) num_bytes; - } -} - -/* Pixma JPEG reader helpers */ -static SANE_Status -pixma_jpeg_start(pixma_sane_t *s) -{ - pixma_jpeg_src_mgr *mgr; - - s->jpeg_cinfo.err = jpeg_std_error(&s->jpeg_err); - - jpeg_create_decompress(&s->jpeg_cinfo); - - s->jpeg_cinfo.src = (struct jpeg_source_mgr *)(*s->jpeg_cinfo.mem->alloc_small)((j_common_ptr)&s->jpeg_cinfo, - JPOOL_PERMANENT, sizeof(pixma_jpeg_src_mgr)); - - memset(s->jpeg_cinfo.src, 0, sizeof(pixma_jpeg_src_mgr)); - - mgr = (pixma_jpeg_src_mgr *)s->jpeg_cinfo.src; - mgr->s = s; - - mgr->buffer = (JOCTET *)(*s->jpeg_cinfo.mem->alloc_small)((j_common_ptr)&s->jpeg_cinfo, - JPOOL_PERMANENT, - 1024 * sizeof(JOCTET)); - - mgr->jpeg.init_source = jpeg_init_source; - mgr->jpeg.fill_input_buffer = jpeg_fill_input_buffer; - mgr->jpeg.skip_input_data = jpeg_skip_input_data; - mgr->jpeg.resync_to_restart = jpeg_resync_to_restart; - mgr->jpeg.term_source = jpeg_term_source; - mgr->jpeg.bytes_in_buffer = 0; - mgr->jpeg.next_input_byte = NULL; - - s->jpeg_header_seen = 0; - - return SANE_STATUS_GOOD; -} - -static SANE_Status -pixma_jpeg_read_header(pixma_sane_t *s) -{ - pixma_jpeg_src_mgr *src = (pixma_jpeg_src_mgr *)s->jpeg_cinfo.src; - - if (jpeg_read_header(&s->jpeg_cinfo, TRUE)) - { - s->jdst = sanei_jpeg_jinit_write_ppm(&s->jpeg_cinfo); - - if (jpeg_start_decompress(&s->jpeg_cinfo)) - { - int size; - - DBG(3, "%s: w: %d, h: %d, components: %d\n", - __func__, - s->jpeg_cinfo.output_width, s->jpeg_cinfo.output_height, - s->jpeg_cinfo.output_components); - - size = s->jpeg_cinfo.output_width * s->jpeg_cinfo.output_components * 1; - - src->linebuffer = (*s->jpeg_cinfo.mem->alloc_large)((j_common_ptr)&s->jpeg_cinfo, - JPOOL_PERMANENT, size); - - src->linebuffer_size = 0; - src->linebuffer_index = 0; - - s->jpeg_header_seen = 1; - - return SANE_STATUS_GOOD; - } - else - { - DBG(0, "%s: decompression failed\n", __func__); - return SANE_STATUS_IO_ERROR; - } - } - else - { - DBG(0, "%s: cannot read JPEG header\n", __func__); - return SANE_STATUS_IO_ERROR; - } -} - -static void -pixma_jpeg_finish(pixma_sane_t *ss) -{ - jpeg_destroy_decompress(&ss->jpeg_cinfo); -} - -static void -pixma_jpeg_read(pixma_sane_t *ss, SANE_Byte *data, - SANE_Int max_length, SANE_Int *length) -{ - struct jpeg_decompress_struct cinfo = ss->jpeg_cinfo; - pixma_jpeg_src_mgr *src = (pixma_jpeg_src_mgr *)ss->jpeg_cinfo.src; - - int l; - - *length = 0; - - /* copy from line buffer if available */ - if (src->linebuffer_size && src->linebuffer_index < src->linebuffer_size) - { - *length = src->linebuffer_size - src->linebuffer_index; - - if (*length > max_length) - *length = max_length; - - memcpy(data, src->linebuffer + src->linebuffer_index, *length); - src->linebuffer_index += *length; - - return; - } - - if (cinfo.output_scanline >= cinfo.output_height) - { - *length = 0; - return; - } - - /* scanlines of decompressed data will be in ss->jdst->buffer - * only one line at time is supported - */ - - l = jpeg_read_scanlines(&cinfo, ss->jdst->buffer, 1); - if (l == 0) - return; - - /* from ss->jdst->buffer to linebuffer - * linebuffer holds width * bytesperpixel - */ - - (*ss->jdst->put_pixel_rows)(&cinfo, ss->jdst, 1, (char *)src->linebuffer); - - *length = ss->sp.w * ss->sp.channels; - /* Convert RGB into grayscale */ - if (ss->sp.channels == 1) - { - unsigned int i; - unsigned char *d = (unsigned char *)src->linebuffer; - unsigned char *s = (unsigned char *)src->linebuffer; - for (i = 0; i < ss->sp.w; i++) - { - /* Using BT.709 luma formula, fixed-point */ - int sum = ( s[0]*2126 + s[1]*7152 + s[2]*722 ); - *d = sum / 10000; - d ++; - s += 3; - } - } - - /* Maybe pack into lineary binary image */ - if (ss->sp.depth == 1) - { - *length /= 8; - unsigned int i; - unsigned char *d = (unsigned char *)src->linebuffer; - unsigned char *s = (unsigned char *)src->linebuffer; - unsigned char b = 0; - for (i = 1; i < ss->sp.w + 1; i++) - { - if (*(s++) > 127) - b = (b << 1) | 0; - else - b = (b << 1) | 1; - } - if ((i % 8) == 0) - *(d++) = b; - } - - src->linebuffer_size = *length; - src->linebuffer_index = 0; - - if (*length > max_length) - *length = max_length; - - memcpy(data, src->linebuffer + src->linebuffer_index, *length); - src->linebuffer_index += *length; -} - - - -static SANE_Status -read_image (pixma_sane_t * ss, void *buf, unsigned size, int *readlen) -{ - int count, status; - - if (readlen) - *readlen = 0; - if (ss->image_bytes_read >= ss->sp.image_size) - return SANE_STATUS_EOF; - - do - { - if (ss->cancel) - /* ss->rpipe has already been closed by sane_cancel(). */ - return SANE_STATUS_CANCELLED; - if (ss->sp.mode_jpeg && !ss->jpeg_header_seen) - { - status = pixma_jpeg_read_header(ss); - if (status != SANE_STATUS_GOOD) - { - close (ss->rpipe); - pixma_jpeg_finish(ss); - ss->rpipe = -1; - if (sanei_thread_is_valid (terminate_reader_task (ss, &status)) - && status != SANE_STATUS_GOOD) - { - return status; - } - else - { - /* either terminate_reader_task failed or - rpipe was closed but we expect more data */ - return SANE_STATUS_IO_ERROR; - } - } - } - - if (ss->sp.mode_jpeg) - { - count = -1; - pixma_jpeg_read(ss, buf, size, &count); - } - else - count = read (ss->rpipe, buf, size); - } - while (count == -1 && errno == EINTR); - - if (count == -1) - { - if (errno == EAGAIN) - return SANE_STATUS_GOOD; - if (!ss->cancel) - { - PDBG (pixma_dbg (1, "WARNING:read_image():read() failed %s\n", - strerror (errno))); - } - close (ss->rpipe); - ss->rpipe = -1; - terminate_reader_task (ss, NULL); - if (ss->sp.mode_jpeg) - pixma_jpeg_finish(ss); - return SANE_STATUS_IO_ERROR; - } - - /* here count >= 0 */ - ss->image_bytes_read += count; - if (ss->image_bytes_read > ss->sp.image_size) - { - PDBG (pixma_dbg (1, "BUG:ss->image_bytes_read > ss->sp.image_size\n")); - } - if (ss->image_bytes_read >= ss->sp.image_size) - { - close (ss->rpipe); - ss->rpipe = -1; - terminate_reader_task (ss, NULL); - if (ss->sp.mode_jpeg) - pixma_jpeg_finish(ss); - } - else if (count == 0) - { - PDBG (pixma_dbg (3, "read_image():reader task closed the pipe:%" - PRIu64" bytes received, %"PRIu64" bytes expected\n", - ss->image_bytes_read, ss->sp.image_size)); - close (ss->rpipe); - if (ss->sp.mode_jpeg) - pixma_jpeg_finish(ss); - ss->rpipe = -1; - if (sanei_thread_is_valid (terminate_reader_task (ss, &status)) - && status != SANE_STATUS_GOOD) - { - return status; - } - else - { - /* either terminate_reader_task failed or - rpipe was closed but we expect more data */ - return SANE_STATUS_IO_ERROR; - } - } - if (readlen) - *readlen = count; - return SANE_STATUS_GOOD; -} - - -/******************************************************************* - ** SANE API - *******************************************************************/ -SANE_Status -sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) -{ - int status, myversion, i; - SANEI_Config config; - - UNUSED (authorize); - - if (!version_code) - return SANE_STATUS_INVAL; - myversion = 100 * PIXMA_VERSION_MAJOR + PIXMA_VERSION_MINOR; - *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, myversion); - DBG_INIT (); - sanei_thread_init (); - pixma_set_debug_level (DBG_LEVEL); - - PDBG(pixma_dbg(2, "pixma is compiled %s pthread support.\n", - (sanei_thread_is_forked () ? "without" : "with"))); - - for (i = 0; i < MAX_CONF_DEVICES; i++) - conf_devices[i] = NULL; - - config.count = 0; - config.descriptors = NULL; - config.values = NULL; - - if (sanei_configure_attach(PIXMA_CONFIG_FILE, &config, config_attach_pixma) != - SANE_STATUS_GOOD) - PDBG(pixma_dbg(2, "Could not read pixma configuration file: %s\n", - PIXMA_CONFIG_FILE)); - - status = pixma_init (); - if (status < 0) - { - PDBG (pixma_dbg (2, "pixma_init() failed %s\n", pixma_strerror (status))); - } - return map_error (status); -} - -void -sane_exit (void) -{ - while (first_scanner) - sane_close (first_scanner); - cleanup_device_list (); - pixma_cleanup (); -} - -SANE_Status -sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) -{ - UNUSED (local_only); - - if (!device_list) - return SANE_STATUS_INVAL; - find_scanners (); - *device_list = dev_list; - return (dev_list) ? SANE_STATUS_GOOD : SANE_STATUS_NO_MEM; -} - -SANE_Status -sane_open (SANE_String_Const name, SANE_Handle * h) -{ - unsigned i, j, nscanners; - int error = 0; - pixma_sane_t *ss = NULL; - const pixma_config_t *cfg; - - if (!name || !h) - return SANE_STATUS_INVAL; - - *h = NULL; - nscanners = pixma_find_scanners (conf_devices); - if (nscanners == 0) - return SANE_STATUS_INVAL; - if (name[0] == '\0') - name = pixma_get_device_id (0); - - /* Have we already opened the scanner? */ - for (ss = first_scanner; ss; ss = ss->next) - { - if (strcmp (pixma_get_string (ss->s, PIXMA_STRING_ID), name) == 0) - { - /* We have already opened it! */ - return SANE_STATUS_DEVICE_BUSY; - } - } - - i = 0; - while (strcmp (pixma_get_device_id (i), name) != 0) - { - if (++i >= nscanners) - return SANE_STATUS_INVAL; - } - cfg = pixma_get_device_config (i); - if ((cfg->cap & PIXMA_CAP_EXPERIMENT) != 0) - { -#ifndef NDEBUG - pixma_dbg (1, "WARNING:" - "Experimental backend CAN DAMAGE your hardware!\n"); - if (getenv_atoi ("PIXMA_EXPERIMENT", 0) == 0) - { - pixma_dbg (1, "Experimental SANE backend for %s is disabled " - "by default.\n", pixma_get_device_model (i)); - pixma_dbg (1, "To enable it, set the environment variable " - "PIXMA_EXPERIMENT to non-zero.\n"); - return SANE_STATUS_UNSUPPORTED; - } -#else - return SANE_STATUS_UNSUPPORTED; -#endif - } - - ss = (pixma_sane_t *) calloc (1, sizeof (*ss)); - if (!ss) - return SANE_STATUS_NO_MEM; - ss->next = first_scanner; - first_scanner = ss; - sanei_thread_initialize (ss->reader_taskid); - ss->wpipe = -1; - ss->rpipe = -1; - ss->idle = SANE_TRUE; - ss->scanning = SANE_FALSE; - ss->sp.frontend_cancel = SANE_FALSE; - for (j=0; j < BUTTON_GROUP_SIZE; j++) - ss->button_option_is_cached[j] = 0; - error = pixma_open (i, &ss->s); - if (error < 0) - { - sane_close (ss); - return map_error (error); - } - pixma_enable_background (ss->s, 0); - init_option_descriptors (ss); - *h = ss; - return SANE_STATUS_GOOD; -} - -void -sane_close (SANE_Handle h) -{ - pixma_sane_t **p, *ss; - - for (p = &first_scanner; *p && *p != (pixma_sane_t *) h; p = &((*p)->next)) - { - } - if (!(*p)) - return; - ss = *p; - sane_cancel (ss); - pixma_close (ss->s); - *p = ss->next; - free (ss); -} - -const SANE_Option_Descriptor * -sane_get_option_descriptor (SANE_Handle h, SANE_Int n) -{ - DECL_CTX; - - if (ss && 0 <= n && n < opt_last) - return &SOD (n); - return NULL; -} - -SANE_Status -sane_control_option (SANE_Handle h, SANE_Int n, - SANE_Action a, void *v, SANE_Int * i) -{ - DECL_CTX; - SANE_Int info = 0; - int error; - option_descriptor_t *opt; - - if (i) - *i = 0; - if (!ss) - return SANE_STATUS_INVAL; - if (n < 0 || n >= opt_last) - return SANE_STATUS_UNSUPPORTED; - if (!ss->idle && a != SANE_ACTION_GET_VALUE) - { - PDBG (pixma_dbg (3, "Warning: !idle && !SANE_ACTION_GET_VALUE\n")); - if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP) - return SANE_STATUS_INVAL; - } - - opt = &(OPT_IN_CTX[n]); - if (!SANE_OPTION_IS_ACTIVE (opt->sod.cap)) - return SANE_STATUS_INVAL; - switch (a) - { - case SANE_ACTION_SET_VALUE: - if ((opt->sod.type != SANE_TYPE_BUTTON && !v) || - !SANE_OPTION_IS_SETTABLE (opt->sod.cap)) - return SANE_STATUS_INVAL; /* or _UNSUPPORTED? */ - break; - case SANE_ACTION_SET_AUTO: - if (!(opt->sod.cap & SANE_CAP_AUTOMATIC) || - !SANE_OPTION_IS_SETTABLE (opt->sod.cap)) - return SANE_STATUS_INVAL; /* or _UNSUPPORTED? */ - break; - case SANE_ACTION_GET_VALUE: - if (!v || !(opt->sod.cap & SANE_CAP_SOFT_DETECT)) - return SANE_STATUS_INVAL; /* or _UNSUPPORTED? */ - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - - error = control_option (ss, n, a, v, &info); - if (error == SANE_STATUS_GOOD && i) - *i = info; - return error; -} - -SANE_Status -sane_get_parameters (SANE_Handle h, SANE_Parameters * p) -{ - DECL_CTX; - pixma_scan_param_t temp, *sp; - - if (!ss || !p) - return SANE_STATUS_INVAL; - - if (!ss->idle) - { - sp = &ss->sp; /* sp is calculated in sane_start() */ - } - else - { - calc_scan_param (ss, &temp); - sp = &temp; - } - p->format = (sp->channels == 3) ? SANE_FRAME_RGB : SANE_FRAME_GRAY; - p->last_frame = SANE_TRUE; - p->lines = sp->h; - p->depth = sp->depth; - p->pixels_per_line = sp->w; - /* p->bytes_per_line = sp->line_size; NOTE: It should work this way, but it doesn't. No SANE frontend can cope with this. */ - p->bytes_per_line = (sp->w * sp->channels * sp->depth) / 8; - return SANE_STATUS_GOOD; -} - -SANE_Status -sane_start (SANE_Handle h) -{ - DECL_CTX; - int error = 0; - - if (!ss) - return SANE_STATUS_INVAL; - if (!ss->idle && ss->scanning) - { - PDBG (pixma_dbg (3, "Warning in Sane_start: !idle && scanning. idle=%d, ss->scanning=%d\n", - ss->idle, ss->scanning)); - if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP) - return SANE_STATUS_INVAL; - } - - ss->cancel = SANE_FALSE; - if (ss->idle || - ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_FLATBED || - ss->source_map[OVAL (opt_source).w] == PIXMA_SOURCE_TPU) - ss->page_count = 0; /* start from idle state or scan from flatbed or TPU */ - else - ss->page_count++; - if (calc_scan_param (ss, &ss->sp) < 0) - return SANE_STATUS_INVAL; - - /* Prepare the JPEG decompressor, if needed */ - if (ss->sp.mode_jpeg) - { - SANE_Status status; - status = pixma_jpeg_start(ss); - if (status != SANE_STATUS_GOOD) - { - PDBG (pixma_dbg(1, "%s: pixma_jpeg_start: %s\n", __func__, sane_strstatus(status)) ); - return status; - } - } - - ss->image_bytes_read = 0; - /* TODO: Check paper here in sane_start(). A function like - pixma_get_status() is needed. */ - error = start_reader_task (ss); - if (error >= 0) - { - ss->output_line_size = (ss->sp.w * ss->sp.channels * ss->sp.depth) / 8; - ss->byte_pos_in_line = 0; - ss->last_read_status = SANE_STATUS_GOOD; - ss->scanning = SANE_TRUE; - ss->idle = SANE_FALSE; - if (ss->sp.mode_jpeg && !ss->jpeg_header_seen) - { - SANE_Status status; - status = pixma_jpeg_read_header(ss); - if (status != SANE_STATUS_GOOD) - { - close (ss->rpipe); - pixma_jpeg_finish(ss); - ss->rpipe = -1; - if (sanei_thread_is_valid (terminate_reader_task (ss, &error)) - && error != SANE_STATUS_GOOD) - { - return error; - } - } - } - } - return map_error (error); -} - -SANE_Status -sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) -{ - DECL_CTX; - int sum, n; - /* Due to 32 pixels alignment, sizeof(temp) is to be greater than: - * max(nchannels) * max (sp.line_size - output_line_size) - * so currently: 3 * 32 = 96 for better end line cropping efficiency */ - SANE_Byte temp[100]; - SANE_Status status; - - if (len) - *len = 0; - if (!ss || !buf || !len) - return SANE_STATUS_INVAL; - if (ss->cancel) - return SANE_STATUS_CANCELLED; - if ((ss->idle) - && (ss->sp.source == PIXMA_SOURCE_ADF || ss->sp.source == PIXMA_SOURCE_ADFDUP)) - return SANE_STATUS_INVAL; - if (!ss->scanning) - return ss->last_read_status; - - status = SANE_STATUS_GOOD; - /* CCD scanners use software lineart - * the scanner must scan 24 bit color or 8 bit grayscale for one bit lineart */ - if ((ss->sp.line_size - ((ss->sp.software_lineart == 1) ? (ss->output_line_size * 8) : ss->output_line_size)) == 0) - { - status = read_image (ss, buf, maxlen, &sum); - } - else - { - /* FIXME: Because there is no frontend that can cope with padding at - the end of line, we've to remove it here in the backend! */ - PDBG (pixma_dbg (1, "*sane_read***** Warning: padding may cause incomplete scan results\n")); - sum = 0; - while (sum < maxlen) - { - if (ss->byte_pos_in_line < ss->output_line_size) - { - n = ss->output_line_size - ss->byte_pos_in_line; - if ((maxlen - sum) < n) - n = maxlen - sum; - status = read_image (ss, buf, n, &n); - if (n == 0) - break; - sum += n; - buf += n; - ss->byte_pos_in_line += n; - } - else - { - /* skip padding */ - n = ss->sp.line_size - ss->byte_pos_in_line; - if (n > (int) sizeof (temp)) - { - PDBG (pixma_dbg (3, "Inefficient skip buffer. Should be %d\n", n)); - n = sizeof (temp); - } - status = read_image (ss, temp, n, &n); - if (n == 0) - break; - ss->byte_pos_in_line += n; - if (ss->byte_pos_in_line == ss->sp.line_size) - ss->byte_pos_in_line = 0; - } - } - } - if (ss->cancel) - status = SANE_STATUS_CANCELLED; - else if ((status == SANE_STATUS_GOOD || status == SANE_STATUS_EOF) && - sum > 0) - { - *len = sum; - status = SANE_STATUS_GOOD; - } - ss->scanning = (status == SANE_STATUS_GOOD); - ss->last_read_status = status; - return status; -} - -void -sane_cancel (SANE_Handle h) -{ - DECL_CTX; - - if (!ss) - return; - ss->cancel = SANE_TRUE; - ss->sp.frontend_cancel = SANE_TRUE; - if (ss->idle) - return; - close (ss->rpipe); - if (ss->sp.mode_jpeg) - pixma_jpeg_finish(ss); - ss->rpipe = -1; - terminate_reader_task (ss, NULL); - ss->idle = SANE_TRUE; -} - -SANE_Status -sane_set_io_mode (SANE_Handle h, SANE_Bool m) -{ - DECL_CTX; - - if (!ss || ss->idle || ss->rpipe == -1) - return SANE_STATUS_INVAL; -#ifdef HAVE_FCNTL_H - PDBG (pixma_dbg (2, "Setting %sblocking mode\n", (m) ? "non-" : "")); - if (fcntl (ss->rpipe, F_SETFL, (m) ? O_NONBLOCK : 0) == -1) - { - PDBG (pixma_dbg - (1, "WARNING:fcntl(F_SETFL) failed %s\n", strerror (errno))); - return SANE_STATUS_UNSUPPORTED; - } - return SANE_STATUS_GOOD; -#else - return (m) ? SANE_STATUS_UNSUPPORTED : SANE_STATUS_GOOD; -#endif -} - -SANE_Status -sane_get_select_fd (SANE_Handle h, SANE_Int * fd) -{ - DECL_CTX; - - *fd = -1; - if (!ss || !fd || ss->idle || ss->rpipe == -1) - return SANE_STATUS_INVAL; - *fd = ss->rpipe; - return SANE_STATUS_GOOD; -} - -/* -BEGIN SANE_Option_Descriptor - -rem ------------------------------------------- -type group - title Scan mode - -type int resolution - unit dpi - constraint @word_list = ss->dpi_list - default 75 - title @SANE_TITLE_SCAN_RESOLUTION - desc @SANE_DESC_SCAN_RESOLUTION - cap soft_select soft_detect automatic - info reload_params - -type string mode[30] - constraint @string_list = ss->mode_list - default @s = SANE_VALUE_SCAN_MODE_COLOR - title @SANE_TITLE_SCAN_MODE - desc @SANE_DESC_SCAN_MODE - cap soft_select soft_detect automatic - info reload_params - -type string source[30] - constraint @string_list = ss->source_list - title @SANE_TITLE_SCAN_SOURCE - desc Selects the scan source (such as a document-feeder). Set source before mode and resolution. Resets mode and resolution to auto values. - default Flatbed - cap soft_select soft_detect - -type bool button-controlled - title Button-controlled scan - desc When enabled, scan process will not start immediately. To proceed, press \"SCAN\" button (for MP150) or \"COLOR\" button (for other models). To cancel, press \"GRAY\" button. - default SANE_FALSE - cap soft_select soft_detect inactive - -rem ------------------------------------------- -type group - title Gamma - -type bool custom-gamma - default SANE_TRUE - title @SANE_TITLE_CUSTOM_GAMMA - desc @SANE_DESC_CUSTOM_GAMMA - cap soft_select soft_detect automatic inactive - -type int gamma-table[4096] - constraint (0,255,0) - title @SANE_TITLE_GAMMA_VECTOR - desc @SANE_DESC_GAMMA_VECTOR - cap soft_select soft_detect automatic inactive - -type fixed gamma - default AUTO_GAMMA - constraint (0.3,5,0) - title Gamma function exponent - desc Changes intensity of midtones - cap soft_select soft_detect automatic inactive - -rem ------------------------------------------- -type group - title Geometry - -type fixed tl-x - unit mm - default 0 - constraint @range = &ss->xrange - title @SANE_TITLE_SCAN_TL_X - desc @SANE_DESC_SCAN_TL_X - cap soft_select soft_detect automatic - info reload_params - -type fixed tl-y - unit mm - default 0 - constraint @range = &ss->yrange - title @SANE_TITLE_SCAN_TL_Y - desc @SANE_DESC_SCAN_TL_Y - cap soft_select soft_detect automatic - info reload_params - -type fixed br-x - unit mm - default _MAX - constraint @range = &ss->xrange - title @SANE_TITLE_SCAN_BR_X - desc @SANE_DESC_SCAN_BR_X - cap soft_select soft_detect automatic - info reload_params - -type fixed br-y - unit mm - default _MAX - constraint @range = &ss->yrange - title @SANE_TITLE_SCAN_BR_Y - desc @SANE_DESC_SCAN_BR_Y - cap soft_select soft_detect automatic - info reload_params - -rem ------------------------------------------- -type group - title Buttons - -type button button-update - title Update button state - cap soft_select soft_detect advanced - -type int button-1 - default 0 - title Button 1 - cap soft_detect advanced - -type int button-2 - default 0 - title Button 2 - cap soft_detect advanced - -type int original - default 0 - title Type of original to scan - cap soft_detect advanced - -type int target - default 0 - title Target operation type - cap soft_detect advanced - -type int scan-resolution - default 0 - title Scan resolution - cap soft_detect advanced - -rem ------------------------------------------- -type group - title Extras - -type int threshold - unit PERCENT - default 50 - constraint (0,100,1) - title @SANE_TITLE_THRESHOLD - desc @SANE_DESC_THRESHOLD - cap soft_select soft_detect automatic inactive - -type int threshold-curve - constraint (0,127,1) - title Threshold curve - desc Dynamic threshold curve, from light to dark, normally 50-65 - cap soft_select soft_detect automatic inactive - -type int adf-wait - default 0 - constraint (0,3600,1) - title ADF Waiting Time - desc When set, the scanner searches the waiting time in seconds for a new document inserted into the automatic document feeder. - cap soft_select soft_detect automatic inactive - -rem ------------------------------------------- -END SANE_Option_Descriptor -*/ - -/* pixma_sane_options.c generated by - * scripts/pixma_gen_options.py < pixma.c > pixma_sane_options.c - * - * pixma_sane_options.h generated by - * scripts/pixma_gen_options.py h < pixma.c > pixma_sane_options.h - */ -#include "pixma_sane_options.c" -- cgit v1.2.3