diff options
Diffstat (limited to 'backend/pixma_common.c')
-rw-r--r-- | backend/pixma_common.c | 1187 |
1 files changed, 0 insertions, 1187 deletions
diff --git a/backend/pixma_common.c b/backend/pixma_common.c deleted file mode 100644 index 82c4fde..0000000 --- a/backend/pixma_common.c +++ /dev/null @@ -1,1187 +0,0 @@ -/* SANE - Scanner Access Now Easy. - - Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de> - Copyright (C) 2007-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org> - Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de> - - 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <math.h> /* pow(C90) */ - -#include <sys/time.h> /* gettimeofday(4.3BSD) */ -#include <unistd.h> /* usleep */ - -#include "pixma_rename.h" -#include "pixma_common.h" -#include "pixma_io.h" - -#include "../include/sane/sanei_usb.h" - - -#ifdef __GNUC__ -# define UNUSED(v) (void) v -#else -# define UNUSED(v) -#endif - -extern const pixma_config_t pixma_mp150_devices[]; -extern const pixma_config_t pixma_mp750_devices[]; -extern const pixma_config_t pixma_mp730_devices[]; -extern const pixma_config_t pixma_mp810_devices[]; -extern const pixma_config_t pixma_iclass_devices[]; - -static const pixma_config_t *const pixma_devices[] = { - pixma_mp150_devices, - pixma_mp750_devices, - pixma_mp730_devices, - pixma_mp810_devices, - pixma_iclass_devices, - NULL -}; - -static pixma_t *first_pixma = NULL; -static time_t tstart_sec = 0; -static uint32_t tstart_usec = 0; -static int debug_level = 1; - - -#ifndef NDEBUG - -static void -u8tohex (uint8_t x, char *str) -{ - static const char hdigit[16] = - { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', - 'e', 'f' - }; - str[0] = hdigit[(x >> 4) & 0xf]; - str[1] = hdigit[x & 0xf]; - str[2] = '\0'; -} - -static void -u32tohex (uint32_t x, char *str) -{ - u8tohex (x >> 24, str); - u8tohex (x >> 16, str + 2); - u8tohex (x >> 8, str + 4); - u8tohex (x, str + 6); -} - -void -pixma_hexdump (int level, const void *d_, unsigned len) -{ - const uint8_t *d = (const uint8_t *) (d_); - unsigned ofs, c, plen; - char line[100]; /* actually only 1+8+1+8*3+1+8*3+1 = 61 bytes needed */ - - if (level > debug_level) - return; - if (level == debug_level) - /* if debuglevel == exact match and buffer contains more than 3 lines, print 2 lines + .... */ - plen = (len > 64) ? 32: len; - else - plen = len; - ofs = 0; - while (ofs < plen) - { - char *p; - line[0] = ' '; - u32tohex (ofs, line + 1); - line[9] = ':'; - p = line + 10; - for (c = 0; c != 16 && (ofs + c) < plen; c++) - { - u8tohex (d[ofs + c], p); - p[2] = ' '; - p += 3; - if (c == 7) - { - p[0] = ' '; - p++; - } - } - p[0] = '\0'; - pixma_dbg (level, "%s\n", line); - ofs += c; - } - if (len > plen) - pixma_dbg(level, "......\n"); -} - -static void -time2str (char *buf, unsigned size) -{ - time_t sec; - uint32_t usec; - - pixma_get_time (&sec, &usec); - sec -= tstart_sec; - if (usec >= tstart_usec) - { - usec -= tstart_usec; - } - else - { - usec = 1000000 + usec - tstart_usec; - sec--; - } - snprintf (buf, size, "%lu.%03u", (unsigned long) sec, - (unsigned) (usec / 1000)); -} - -void -pixma_dump (int level, const char *type, const void *data, int len, - int size, int max) -{ - int actual_len, print_len; - char buf[20]; - - if (level > debug_level) - return; - if (debug_level >= 20) - max = -1; /* dump every bytes */ - - time2str (buf, sizeof (buf)); - pixma_dbg (level, "%s T=%s len=%d\n", type, buf, len); - - actual_len = (size >= 0) ? size : len; - print_len = (max >= 0 && max < actual_len) ? max : actual_len; - if (print_len >= 0) - { - pixma_hexdump (level, data, print_len); - if (print_len < actual_len) - pixma_dbg (level, " ...\n"); - } - if (len < 0) - pixma_dbg (level, " ERROR: %s\n", pixma_strerror (len)); - pixma_dbg (level, "\n"); -} - - -#endif /* NDEBUG */ - -/* NOTE: non-reentrant */ -const char * -pixma_strerror (int error) -{ - static char buf[50]; - - /* TODO: more human friendly messages */ - switch (error) - { - case PIXMA_EIO: - return "EIO"; - case PIXMA_ENODEV: - return "ENODEV"; - case PIXMA_EACCES: - return "EACCES"; - case PIXMA_ENOMEM: - return "ENOMEM"; - case PIXMA_EINVAL: - return "EINVAL"; - case PIXMA_EBUSY: - return "EBUSY"; - case PIXMA_ECANCELED: - return "ECANCELED"; - case PIXMA_ENOTSUP: - return "ENOTSUP"; - case PIXMA_ETIMEDOUT: - return "ETIMEDOUT"; - case PIXMA_EPROTO: - return "EPROTO"; - case PIXMA_EPAPER_JAMMED: - return "EPAPER_JAMMED"; - case PIXMA_ECOVER_OPEN: - return "ECOVER_OPEN"; - case PIXMA_ENO_PAPER: - return "ENO_PAPER"; - case PIXMA_EOF: - return "EEOF"; - } - snprintf (buf, sizeof (buf), "EUNKNOWN:%d", error); - return buf; -} - -void -pixma_set_debug_level (int level) -{ - debug_level = level; -} - -void -pixma_set_be16 (uint16_t x, uint8_t * buf) -{ - buf[0] = x >> 8; - buf[1] = x; -} - -void -pixma_set_be32 (uint32_t x, uint8_t * buf) -{ - buf[0] = x >> 24; - buf[1] = x >> 16; - buf[2] = x >> 8; - buf[3] = x; -} - -uint16_t -pixma_get_be16 (const uint8_t * buf) -{ - return ((uint16_t) buf[0] << 8) | buf[1]; -} - -uint32_t -pixma_get_be32 (const uint8_t * buf) -{ - return ((uint32_t) buf[0] << 24) + ((uint32_t) buf[1] << 16) + - ((uint32_t) buf[2] << 8) + buf[3]; -} - -uint8_t -pixma_sum_bytes (const void *data, unsigned len) -{ - const uint8_t *d = (const uint8_t *) data; - unsigned i, sum = 0; - for (i = 0; i != len; i++) - sum += d[i]; - return sum; -} - -void -pixma_sleep (unsigned long usec) -{ - usleep (usec); -} - -void -pixma_get_time (time_t * sec, uint32_t * usec) -{ - struct timeval tv; - gettimeofday (&tv, NULL); - if (sec) - *sec = tv.tv_sec; - if (usec) - *usec = tv.tv_usec; -} - -/* convert 24/48 bit RGB to 8/16 bit ir - * - * Formular: g = R - * drop G + B - * - * sptr: source color scale buffer - * gptr: destination gray scale buffer - * c == 3: 24 bit RGB -> 8 bit ir - * c == 6: 48 bit RGB -> 16 bit ir - */ -uint8_t * -pixma_r_to_ir (uint8_t * gptr, uint8_t * sptr, unsigned w, unsigned c) -{ - unsigned i; - - /* PDBG (pixma_dbg (4, "*pixma_rgb_to_ir*****\n")); */ - - for (i = 0; i < w; i++) - { - *gptr++ = *sptr++; - if (c == 6) *gptr++ = *sptr++; /* 48 bit RGB: high byte */ - sptr += (c == 6) ? 4 : 2; /* drop G + B */ - } - return gptr; -} - -/* convert 24/48 bit RGB to 8/16 bit grayscale - * - * Formular: g = (R + G + B) / 3 - * - * sptr: source color scale buffer - * gptr: destination gray scale buffer - * c == 3: 24 bit RGB -> 8 bit gray - * c == 6: 48 bit RGB -> 16 bit gray - */ -uint8_t * -pixma_rgb_to_gray (uint8_t * gptr, uint8_t * sptr, unsigned w, unsigned c) -{ - unsigned i, j, g; - - /* PDBG (pixma_dbg (4, "*pixma_rgb_to_gray*****\n")); */ - - for (i = 0; i < w; i++) - { - for (j = 0, g = 0; j < 3; j++) - { - g += *sptr++; - if (c == 6) g += (*sptr++ << 8); /* 48 bit RGB: high byte */ - } - - g /= 3; /* 8 or 16 bit gray */ - *gptr++ = g; - if (c == 6) *gptr++ = (g >> 8); /* 16 bit gray: high byte */ - } - return gptr; -} - -/** - * This code was taken from the genesys backend - * uses threshold and threshold_curve to control software binarization - * @param sp device set up for the scan - * @param dst pointer where to store result - * @param src pointer to raw data - * @param width width of the processed line - * @param c 1 for 1-channel single-byte data, - * 3 for 3-channel single-byte data, - * 6 for double-byte data - * */ -uint8_t * -pixma_binarize_line(pixma_scan_param_t * sp, uint8_t * dst, uint8_t * src, unsigned width, unsigned c) -{ - unsigned j, x, windowX, sum = 0; - unsigned threshold; - unsigned offset, addCol; - int dropCol, offsetX; - unsigned char mask; - uint8_t min, max; - - /* PDBG (pixma_dbg (4, "*pixma_binarize_line***** src = %u, dst = %u, width = %u, c = %u, threshold = %u, threshold_curve = %u *****\n", - src, dst, width, c, sp->threshold, sp->threshold_curve)); */ - - /* 16 bit grayscale not supported */ - if (c == 6) - { - PDBG (pixma_dbg (1, "*pixma_binarize_line***** Error: 16 bit grayscale not supported\n")); - return dst; - } - - /* first, color convert to grayscale */ - if (c != 1) - pixma_rgb_to_gray(dst, src, width, c); - - /* second, normalize line */ - min = 255; - max = 0; - for (x = 0; x < width; x++) - { - if (src[x] > max) - { - max = src[x]; - } - if (src[x] < min) - { - min = src[x]; - } - } - - /* safeguard against dark or white areas */ - if(min>80) - min=0; - if(max<80) - max=255; - for (x = 0; x < width; x++) - { - src[x] = ((src[x] - min) * 255) / (max - min); - } - - /* third, create sliding window, prefill the sliding sum */ - /* ~1mm works best, but the window needs to have odd # of pixels */ - windowX = (6 * sp->xdpi) / 150; - if (!(windowX % 2)) - windowX++; - - /* to avoid conflicts with *dst start with offset */ - offsetX = 1 + (windowX / 2) / 8; - for (j = offsetX; j <= windowX; j++) - sum += src[j]; - /* PDBG (pixma_dbg (4, " *pixma_binarize_line***** windowX = %u, startX = %u, sum = %u\n", - windowX, startX, sum)); */ - - /* fourth, walk the input buffer, output bits */ - for (j = 0; j < width; j++) - { - /* output image location */ - offset = j % 8; - mask = 0x80 >> offset; - threshold = sp->threshold; - - /* move sum/update threshold only if there is a curve */ - if (sp->threshold_curve) - { - addCol = j + windowX / 2; - dropCol = addCol - windowX; - - if (dropCol >= offsetX && addCol < width) - { - sum += src[addCol]; - sum -= (sum < src[dropCol] ? sum : src[dropCol]); /* no negative sum */ - } - threshold = sp->lineart_lut[sum / windowX]; - /* PDBG (pixma_dbg (4, " *pixma_binarize_line***** addCol = %u, dropCol = %d, sum = %u, windowX = %u, lut-element = %d, threshold = %u\n", - addCol, dropCol, sum, windowX, sum/windowX, threshold)); */ - } - - /* lookup threshold */ - if (src[j] > threshold) - *dst &= ~mask; /* white */ - else - *dst |= mask; /* black */ - - if (offset == 7) - dst++; - } - - /* PDBG (pixma_dbg (4, " *pixma_binarize_line***** ready: src = %u, dst = %u *****\n", src, dst)); */ - - return dst; -} - -/** - This code was taken from the genesys backend - Function to build a lookup table (LUT), often - used by scanners to implement brightness/contrast/gamma - or by backends to speed binarization/thresholding - - offset and slope inputs are -127 to +127 - - slope rotates line around central input/output val, - 0 makes horizontal line - - pos zero neg - . x . . x - . x . . x - out . x .xxxxxxxxxxx . x - . x . . x - ....x....... ............ .......x.... - in in in - - offset moves line vertically, and clamps to output range - 0 keeps the line crossing the center of the table - - high low - . xxxxxxxx . - . x . - out x . x - . . x - ............ xxxxxxxx.... - in in - - out_min/max provide bounds on output values, - useful when building thresholding lut. - 0 and 255 are good defaults otherwise. - * */ -static SANE_Status -load_lut (unsigned char * lut, - int in_bits, int out_bits, - int out_min, int out_max, - int slope, int offset) -{ - int i, j; - double shift, rise; - int max_in_val = (1 << in_bits) - 1; - int max_out_val = (1 << out_bits) - 1; - unsigned char * lut_p = lut; - - /* PDBG (pixma_dbg (4, "*load_lut***** start %d %d *****\n", slope, offset)); */ - - /* slope is converted to rise per unit run: - * first [-127,127] to [-1,1] - * then multiply by PI/2 to convert to radians - * then take the tangent (T.O.A) - * then multiply by the normal linear slope - * because the table may not be square, i.e. 1024x256*/ - rise = tan((double)slope/127 * M_PI/2) * max_out_val / max_in_val; - - /* line must stay vertically centered, so figure - * out vertical offset at central input value */ - shift = (double)max_out_val/2 - (rise*max_in_val/2); - - /* convert the user offset setting to scale of output - * first [-127,127] to [-1,1] - * then to [-max_out_val/2,max_out_val/2]*/ - shift += (double)offset / 127 * max_out_val / 2; - - for(i=0;i<=max_in_val;i++){ - j = rise*i + shift; - - if(j<out_min){ - j=out_min; - } - else if(j>out_max){ - j=out_max; - } - - *lut_p=j; - lut_p++; - } - - /* PDBG (pixma_dbg (4, "*load_lut***** finish *****\n")); */ - /* PDBG (pixma_hexdump (4, lut, max_in_val+1)); */ - - return SANE_STATUS_GOOD; -} - -int -pixma_map_status_errno (unsigned status) -{ - switch (status) - { - case PIXMA_STATUS_OK: - return 0; - case PIXMA_STATUS_FAILED: - return PIXMA_ECANCELED; - case PIXMA_STATUS_BUSY: - return PIXMA_EBUSY; - default: - return PIXMA_EPROTO; - } -} - -int -pixma_check_result (pixma_cmdbuf_t * cb) -{ - const uint8_t *r = cb->buf; - unsigned header_len = cb->res_header_len; - unsigned expected_reslen = cb->expected_reslen; - int error; - unsigned len; - - if (cb->reslen < 0) - return cb->reslen; - - len = (unsigned) cb->reslen; - if (len >= header_len) - { - error = pixma_map_status_errno (pixma_get_be16 (r)); - if (expected_reslen != 0) - { - if (len == expected_reslen) - { - if (pixma_sum_bytes (r + header_len, len - header_len) != 0) - error = PIXMA_EPROTO; - } - else - { - /* This case will happen when a command cannot be completely - executed, e.g. because you press the cancel button. The - device will return only a header with PIXMA_STATUS_FAILED. */ - if (len != header_len) - error = PIXMA_EPROTO; - } - } - } - else - error = PIXMA_EPROTO; - -#ifndef NDEBUG - if (error == PIXMA_EPROTO) - { - pixma_dbg (1, "WARNING: result len=%d expected %d\n", - len, cb->expected_reslen); - pixma_hexdump (1, r, MIN (len, 64)); - } -#endif - return error; -} - -int -pixma_cmd_transaction (pixma_t * s, const void *cmd, unsigned cmdlen, - void *data, unsigned expected_len) -{ - int error, tmo; - - error = pixma_write (s->io, cmd, cmdlen); - if (error != (int) cmdlen) - { - if (error >= 0) - { - /* Write timeout is too low? */ - PDBG (pixma_dbg - (1, "ERROR: incomplete write, %u out of %u written\n", - (unsigned) error, cmdlen)); - error = PIXMA_ETIMEDOUT; - } - return error; - } - - /* When you send the start_session command while the scanner optic is - going back to the home position after the last scan session has been - cancelled, you won't get the response before it arrives home. This takes - about 5 seconds. If the last session was succeeded, the scanner will - immediatly answer with PIXMA_STATUS_BUSY. - - Is 8 seconds timeout enough? This affects ALL commands that use - pixma_cmd_transaction(). Default value set in pixma_open(). */ - tmo = s->rec_tmo; - do - { - error = pixma_read (s->io, data, expected_len); - if (error == PIXMA_ETIMEDOUT) - { - PDBG (pixma_dbg (2, "No response yet. Timed out in %d sec.\n", tmo)); - -#ifndef HAVE_SANEI_USB_SET_TIMEOUT - /* 1s timeout - Only needed, if sanei_usb_set_timeout() isn't available. - pixma_read() has an internal timeout of 1 sec. */ - pixma_sleep (1000000); -#endif - } - } - while (error == PIXMA_ETIMEDOUT && --tmo != 0); - if (error < 0) - { - PDBG (pixma_dbg (1, "WARNING: Error in response phase. cmd:%02x%02x\n", - ((const uint8_t *) cmd)[0], - ((const uint8_t *) cmd)[1])); - PDBG (pixma_dbg (1," If the scanner hangs, reset it and/or unplug the " - "USB cable.\n")); - } - return error; /* length of the result packet or error */ -} - -uint8_t * -pixma_newcmd (pixma_cmdbuf_t * cb, unsigned cmd, - unsigned dataout, unsigned datain) -{ - unsigned cmdlen = cb->cmd_header_len + dataout; - unsigned reslen = cb->res_header_len + datain; - - if (cmdlen > cb->size || reslen > cb->size) - return NULL; - memset (cb->buf, 0, cmdlen); - cb->cmdlen = cmdlen; - cb->expected_reslen = reslen; - pixma_set_be16 (cmd, cb->buf); - pixma_set_be16 (dataout + datain, cb->buf + cb->cmd_len_field_ofs); - if (dataout != 0) - return cb->buf + cb->cmd_header_len; - else - return cb->buf + cb->res_header_len; -} - -int -pixma_exec (pixma_t * s, pixma_cmdbuf_t * cb) -{ - if (cb->cmdlen > cb->cmd_header_len) - pixma_fill_checksum (cb->buf + cb->cmd_header_len, - cb->buf + cb->cmdlen - 1); - cb->reslen = - pixma_cmd_transaction (s, cb->buf, cb->cmdlen, cb->buf, - cb->expected_reslen); - return pixma_check_result (cb); -} - -int -pixma_exec_short_cmd (pixma_t * s, pixma_cmdbuf_t * cb, unsigned cmd) -{ - pixma_newcmd (cb, cmd, 0, 0); - return pixma_exec (s, cb); -} - -int -pixma_check_dpi (unsigned dpi, unsigned max) -{ - /* valid dpi = 75 * 2^n */ - unsigned temp = dpi / 75; - if (dpi > max || dpi < 75 || 75 * temp != dpi || (temp & (temp - 1)) != 0) - return PIXMA_EINVAL; - return 0; -} - - -int -pixma_init (void) -{ - PDBG (pixma_dbg (2, "pixma version %d.%d.%d\n", PIXMA_VERSION_MAJOR, - PIXMA_VERSION_MINOR, PIXMA_VERSION_BUILD)); - PASSERT (first_pixma == NULL); - if (tstart_sec == 0) - pixma_get_time (&tstart_sec, &tstart_usec); - return pixma_io_init (); -} - -void -pixma_cleanup (void) -{ - while (first_pixma) - pixma_close (first_pixma); - pixma_io_cleanup (); -} - -int -pixma_open (unsigned devnr, pixma_t ** handle) -{ - int error; - pixma_t *s; - const pixma_config_t *cfg; - - *handle = NULL; - cfg = pixma_get_device_config (devnr); - if (!cfg) - return PIXMA_EINVAL; /* invalid devnr */ - PDBG (pixma_dbg (2, "pixma_open(): %s\n", cfg->name)); - - s = (pixma_t *) calloc (1, sizeof (s[0])); - if (!s) - return PIXMA_ENOMEM; - s->next = first_pixma; - first_pixma = s; - - s->cfg = cfg; - s->rec_tmo = 8; /* set receive timeout to 8 seconds */ - error = pixma_connect (devnr, &s->io); - if (error < 0) - { - PDBG (pixma_dbg - (2, "pixma_connect() failed %s\n", pixma_strerror (error))); - goto rollback; - } - strncpy (s->id, pixma_get_device_id (devnr), sizeof (s->id) - 1); - s->ops = s->cfg->ops; - s->scanning = 0; - error = s->ops->open (s); - if (error < 0) - goto rollback; - error = pixma_deactivate (s->io); - if (error < 0) - goto rollback; - *handle = s; - return 0; - -rollback: - PDBG (pixma_dbg (2, "pixma_open() failed %s\n", pixma_strerror (error))); - pixma_close (s); - return error; -} - -void -pixma_close (pixma_t * s) -{ - pixma_t **p; - - if (!s) - return; - for (p = &first_pixma; *p && *p != s; p = &((*p)->next)) - { - } - PASSERT (*p); - if (!(*p)) - return; - PDBG (pixma_dbg (2, "pixma_close(): %s\n", s->cfg->name)); - if (s->io) - { - if (s->scanning) - { - PDBG (pixma_dbg (3, "pixma_close(): scanning in progress, call" - " finish_scan()\n")); - s->ops->finish_scan (s); - } - s->ops->close (s); - pixma_disconnect (s->io); - } - *p = s->next; - free (s); -} - -int -pixma_scan (pixma_t * s, pixma_scan_param_t * sp) -{ - int error; - - error = pixma_check_scan_param (s, sp); - if (error < 0) - return error; - - if (sp->mode == PIXMA_SCAN_MODE_LINEART) - { - load_lut(sp->lineart_lut, 8, 8, 50, 205, - sp->threshold_curve, sp->threshold-127); - } - -#ifndef NDEBUG - pixma_dbg (3, "\n"); - pixma_dbg (3, "pixma_scan(): start\n"); - pixma_dbg (3, " line_size=%"PRIu64" image_size=%"PRIu64" channels=%u depth=%u\n", - sp->line_size, sp->image_size, sp->channels, sp->depth); - pixma_dbg (3, " dpi=%ux%u offset=(%u,%u) dimension=%ux%u\n", - sp->xdpi, sp->ydpi, sp->x, sp->y, sp->w, sp->h); - pixma_dbg (3, " gamma_table=%p source=%d\n", sp->gamma_table, sp->source); - pixma_dbg (3, " threshold=%d threshold_curve=%d\n", sp->threshold, sp->threshold_curve); - pixma_dbg (3, " adf-wait=%d\n", sp->adf_wait); - pixma_dbg (3, " ADF page count: %d\n", sp->adf_pageid); -#endif - - s->param = sp; - s->cancel = 0; - s->cur_image_size = 0; - s->imagebuf.wptr = NULL; - s->imagebuf.wend = NULL; - s->imagebuf.rptr = NULL; - s->imagebuf.rend = NULL; - s->underrun = 0; - error = s->ops->scan (s); - if (error >= 0) - { - s->scanning = 1; - } - else - { - PDBG (pixma_dbg - (3, "pixma_scan() failed %s\n", pixma_strerror (error))); - } - - return error; -} - -static uint8_t * -fill_pixels (pixma_t * s, uint8_t * ptr, uint8_t * end, uint8_t value) -{ - if (s->cur_image_size < s->param->image_size) - { - long n = s->param->image_size - s->cur_image_size; - if (n > (end - ptr)) - n = end - ptr; - memset (ptr, value, n); - s->cur_image_size += n; - ptr += n; - } - return ptr; -} - -int -pixma_read_image (pixma_t * s, void *buf, unsigned len) -{ - int result; - pixma_imagebuf_t ib; - - if (!s->scanning) - return 0; - if (s->cancel) - { - result = PIXMA_ECANCELED; - goto cancel; - } - - ib = s->imagebuf; /* get rptr and rend */ - ib.wptr = (uint8_t *) buf; - ib.wend = ib.wptr + len; - - if (s->underrun) - { - if (s->cur_image_size < s->param->image_size) - { - ib.wptr = fill_pixels (s, ib.wptr, ib.wend, 0xff); - } - else - { - PDBG (pixma_dbg - (3, "pixma_read_image(): completed (underrun detected)\n")); - s->scanning = 0; - } - return ib.wptr - (uint8_t *) buf; - } - - while (ib.wptr != ib.wend) - { - if (ib.rptr == ib.rend) - { - ib.rptr = ib.rend = NULL; - result = s->ops->fill_buffer (s, &ib); - if (result < 0) - goto cancel; - if (result == 0) - { /* end of image? */ - s->ops->finish_scan (s); - if ((s->cur_image_size != s->param->image_size) && !s->param->mode_jpeg) - { - pixma_dbg (1, "WARNING:image size mismatches\n"); - pixma_dbg (1, - " %"PRIu64" expected (%d lines) but %"PRIu64" received (%"PRIu64" lines)\n", - s->param->image_size, s->param->h, - s->cur_image_size, - s->cur_image_size / s->param->line_size); - if ((s->cur_image_size % s->param->line_size) != 0) - { - pixma_dbg (1, - "BUG:received data not multiple of line_size\n"); - } - } - if ((s->cur_image_size < s->param->image_size) && !s->param->mode_jpeg) - { - s->underrun = 1; - ib.wptr = fill_pixels (s, ib.wptr, ib.wend, 0xff); - } - else - { - PDBG (pixma_dbg (3, "pixma_read_image():completed\n")); - s->scanning = 0; - } - break; - } - s->cur_image_size += result; - - PASSERT (s->cur_image_size <= s->param->image_size); - } - if (ib.rptr) - { - unsigned count = MIN (ib.rend - ib.rptr, ib.wend - ib.wptr); - memcpy (ib.wptr, ib.rptr, count); - ib.rptr += count; - ib.wptr += count; - } - } - s->imagebuf = ib; /* store rptr and rend */ - return ib.wptr - (uint8_t *) buf; - -cancel: - s->ops->finish_scan (s); - s->scanning = 0; - if (result == PIXMA_ECANCELED) - { - PDBG (pixma_dbg (3, "pixma_read_image(): cancelled by %sware\n", - (s->cancel) ? "soft" : "hard")); - } - else - { - PDBG (pixma_dbg (3, "pixma_read_image() failed %s\n", - pixma_strerror (result))); - } - return result; -} - -void -pixma_cancel (pixma_t * s) -{ - s->cancel = 1; -} - -int -pixma_enable_background (pixma_t * s, int enabled) -{ - return pixma_set_interrupt_mode (s->io, enabled); -} - -int -pixma_activate_connection(pixma_t * s) -{ - return pixma_activate (s->io); -} - -int -pixma_deactivate_connection(pixma_t * s) -{ - return pixma_deactivate (s->io); -} - -uint32_t -pixma_wait_event (pixma_t * s, int timeout /*ms */ ) -{ - unsigned events; - - if (s->events == PIXMA_EV_NONE && s->ops->wait_event) - s->ops->wait_event (s, timeout); - events = s->events; - s->events = PIXMA_EV_NONE; - return events; -} - -#define CLAMP2(x,w,min,max,dpi) do { \ - unsigned m = (max) * (dpi) / 75; \ - x = MIN(x, m - min); \ - w = MIN(w, m - x); \ - if (w < min) w = min; \ -} while(0) - -int -pixma_check_scan_param (pixma_t * s, pixma_scan_param_t * sp) -{ - unsigned cfg_xdpi; - - if (!(sp->channels == 3 || - (sp->channels == 1 && (s->cfg->cap & PIXMA_CAP_GRAY) != 0))) - return PIXMA_EINVAL; - - /* flatbed: use s->cfg->xdpi - * TPU/ADF: use s->cfg->adftpu_max_dpi, if configured with dpi value */ - cfg_xdpi = ((sp->source == PIXMA_SOURCE_FLATBED - || s->cfg->adftpu_max_dpi == 0) ? s->cfg->xdpi - : s->cfg->adftpu_max_dpi); - - if (pixma_check_dpi (sp->xdpi, cfg_xdpi) < 0 || - pixma_check_dpi (sp->ydpi, s->cfg->ydpi) < 0) - return PIXMA_EINVAL; - - /* xdpi must be equal to ydpi except that - xdpi = max_xdpi and ydpi = max_ydpi. */ - if (!(sp->xdpi == sp->ydpi || - (sp->xdpi == cfg_xdpi && sp->ydpi == s->cfg->ydpi))) - return PIXMA_EINVAL; - - if (s->ops->check_param (s, sp) < 0) - return PIXMA_EINVAL; - - /* FIXME: I assume the same minimum width and height for every model. - * new scanners need minimum 16 px height - * minimum image size: 16 px x 16 px */ - CLAMP2 (sp->x, sp->w, 16, s->cfg->width, sp->xdpi); - CLAMP2 (sp->y, sp->h, 16, s->cfg->height, sp->ydpi); - - switch (sp->source) - { - case PIXMA_SOURCE_FLATBED: - break; - - case PIXMA_SOURCE_TPU: - if ((s->cfg->cap & PIXMA_CAP_TPU) != PIXMA_CAP_TPU) - { - sp->source = PIXMA_SOURCE_FLATBED; - PDBG (pixma_dbg - (1, "WARNING: TPU unsupported, fallback to flatbed.\n")); - } - break; - - case PIXMA_SOURCE_ADF: - if ((s->cfg->cap & PIXMA_CAP_ADF) != PIXMA_CAP_ADF) - { - sp->source = PIXMA_SOURCE_FLATBED; - PDBG (pixma_dbg - (1, "WARNING: ADF unsupported, fallback to flatbed.\n")); - } - break; - - case PIXMA_SOURCE_ADFDUP: - if ((s->cfg->cap & PIXMA_CAP_ADFDUP) != PIXMA_CAP_ADFDUP) - { - if (s->cfg->cap & PIXMA_CAP_ADF) - { - sp->source = PIXMA_SOURCE_ADF; - } - else - { - sp->source = PIXMA_SOURCE_FLATBED; - } - PDBG (pixma_dbg - (1, "WARNING: ADF duplex unsupported, fallback to %d.\n", - sp->source)); - } - break; - } - - if (sp->depth == 0) - sp->depth = 8; - if ((sp->depth % 8) != 0 && sp->depth != 1) - return PIXMA_EINVAL; - - sp->line_size = 0; - - if (s->ops->check_param (s, sp) < 0) - return PIXMA_EINVAL; - - if (sp->line_size == 0) - sp->line_size = sp->depth / 8 * sp->channels * sp->w; - sp->image_size = sp->line_size * sp->h; - - /* image_size for software lineart is counted in bits */ - if (sp->software_lineart == 1) - sp->image_size /= 8; - return 0; -} - -const char * -pixma_get_string (pixma_t * s, pixma_string_index_t i) -{ - switch (i) - { - case PIXMA_STRING_MODEL: - return s->cfg->name; - case PIXMA_STRING_ID: - return s->id; - case PIXMA_STRING_LAST: - return NULL; - } - return NULL; -} - -const pixma_config_t * -pixma_get_config (pixma_t * s) -{ - return s->cfg; -} - -void -pixma_fill_gamma_table (double gamma, uint8_t * table, unsigned n) -{ - int i; - double r_gamma = 1.0 / gamma; - double out_scale = 255.0; - double in_scale = 1.0 / (n - 1); - - for (i = 0; (unsigned) i != n; i++) - { - table[i] = (int) (out_scale * pow (i * in_scale, r_gamma) + 0.5); - } -} - -int -pixma_find_scanners (const char **conf_devices) -{ - return pixma_collect_devices (conf_devices, pixma_devices); -} - -const char * -pixma_get_device_model (unsigned devnr) -{ - const pixma_config_t *cfg = pixma_get_device_config (devnr); - return (cfg) ? cfg->name : NULL; -} - - -int -pixma_get_device_status (pixma_t * s, pixma_device_status_t * status) -{ - if (!status) - return PIXMA_EINVAL; - memset (status, 0, sizeof (*status)); - return s->ops->get_status (s, status); -} |